2014-09-03 4 views
1

Интересно, почему вывод этой C++-программы X: f1? Есть ли вызов объекта y, логично ли вызывать Y f1()? Разве не должно быть наследства? Я запутался ...Почему программа записывает выходные данные следующим образом?

class X { 
    public: 
     void f1() { cout<<"X:f1"<<endl;} 
    }; 
    class Y : public X { 
    public: 
     void f1() { cout<<"Y:f1"<<endl;} 
    }; 
    Y* y = new Y(); 
    void f(X* x) { x -> f1(); } 
    int main() { f (y); 
    system("pause"); 
    return 1; 
    } 

И как изменить тело функции и аргументов он принимает, чтобы получить Y F(): f1 на выходе?

+4

Объявление функции 'f1()' как 'virtual' – CoryKramer

+2

Если вы используете язык Java, Python и т. Д., Где все методы экземпляра являются виртуальными, тогда вы должны прочитать о них. – mostruash

ответ

4

Вы получаете эту проблему, потому что функция не объявлена ​​виртуальной. Вам нужно добавить квалификатор virtual в X's f1, чтобы позволить подклассам переопределять его.

class X { 
public: 
    virtual void f1() { cout<<"X:f1"<<endl;} 
}; 

class Y : public X { 
public: 
    virtual void f1() { cout<<"Y:f1"<<endl;} 
}; 

Если вы этого не сделаете, Y «s f1 будет вызываться только если компилятор знает о типе объекта. Это не тот случай, когда вы конвертируете его в . Это поведение, которое вы наблюдаете:

Y* y = new Y; 
y->f1(); // prints "Y:f1" 
X* x = y; 
x->f1(); // prints "X:f1"! 
+0

Спасибо за ответ :) – anicicn

7

Поскольку X::f1 не virtual, вызывает к нему статический отправлено, то есть в этом случае они будут направлены на основе статического типа x (который X), а не его динамический тип (который в этом случае равен Y).

Другими словами, потому что X::f1 не virtual, тот факт, что x указывает на экземпляр Y при вызове f(y) не принимается во внимание - компилятор отправляет все вызовы X::f1 в X «s f1 независимо от динамический (т. е. время выполнения) объекта, на который указывает x.

В отличие от других языков (например, Java), функции-члены в C++ не являются virtual по умолчанию - вам нужно явно указать, что вы хотите, чтобы подклассы могли их переопределять.

Чтобы получить результат вы ожидаете, что вам нужно добавить virtual спецификатора X::f1 - вы не можете разумно добиться того, что вы хотите, изменяя только тело f, как вы предлагаете, потому что вы отбрасывая информацию о x ' динамический тип, но вы можете изменить аргументы f, чтобы принять Y*, а не в данном конкретном случае.

+1

Да, вы правы. Большое спасибо, я просто забыл эту «крошечную» деталь :) Привет! – anicicn

+1

@anicicn Это ** конечно не ** a _tiny detail_, но очень фундаментальная точка в программировании на C++! –

+0

Действительно ли это ответ на вопрос? – Slava

0

я попробовал ваш код в моем компиляторе таким образом

#include<iostream> 
using namespace std; 
class X { 
public: 
    virtual void f1() { cout<<"X:f1"<<endl;} 
    // ^^^^^^^ Note my changes here! 
}; 
class Y : public X { 
public: 
    void f1() { cout<<"Y:f1"<<endl;} 
}; 

Y* y = new Y(); 
void f(X* x) { x -> f1(); } 

int main() { 
    f(y); 
    return 1 ; 
} 

и выход Y:F1 не X:F1, как у сказал попробовать это снова,

+1

Это не мой код, который я опубликовал. Вы вставили виртуальный, которого у меня нет в сообщении выше. – anicicn

+0

@anicicn Да, это было пропущено, чтобы указать на это. Исправлена. –

+0

@ omar-khaled Лучше на 1-й снимок в следующий раз! –

1

И как изменить тело F() функции и аргументы, необходимые для получения Y: f1 на выходе?

Фактический ответ на ваш вопрос:

void f(Y* y) { y -> f1(); } 

Хотя нет особого смысла иметь нон виртуальный метод с таким же именем и подписью в производном классе, кроме как производить трудно уловить проблемы.

Смежные вопросы