2014-01-20 2 views
0

Я получил эту треску:C++ виртуальных функций неожиданного поведения

class First{ 
public: 
    virtual void print(){cout<<"First";} 

}; 

class Second : public First { 
public: 
    virtual void print(){cout<<"Second";} 


}; 
class Third : public Second{ 
public: 
    void print(){cout<<"Third";} 

    int main(){ 
    Third ob; 
    ob.print(); 
    Second& sec=ob; 
    sec.print(); 
    First& frs=ob; 
    frs.print(); 
} 

Все получается как я ожидал, все 3 печатей: «третьих».

Теперь, потому что у меня слишком много кода, и это в основном то же самое с небольшим изменением, я обсужу его в тексте.

Теперь я удаляю виртуальную печать с первой, и она печатает: «Третья Третья», как я и ожидал.

Этот третий раз, я вернул виртуальный первый, но я удаляю его со второго. Теперь он печатает: «Третья Третья Третья». Хм, это не то, чего я ожидал. Предположим, что когда со ссылкой First он видит, что функция виртуальна, он затем проверяет объекты и вызывает метод для третьего, но когда со ссылкой Second он видит, что функция не является виртуальной, почему она все еще вызывает печать третьего?

+0

Это потому, что вы используете ссылку Третьего объекта. даже если вы задали тип времени выполнения, vtable все еще видит его третьим. – Gasim

+5

Функция в 'Second' неявно виртуальна, так как имеет ту же подпись, что и функция в' First'. – dyp

+0

Обратите внимание, что отметка 'print' в' Second' как 'final' даст вам ясную ошибку, когда появится' Third'. – chris

ответ

4

Если функция переопределяет виртуальную функцию, то она является виртуальной, независимо от того, явно ли вы это объявили. Итак, здесь Second::print является виртуальным, однако вы его заявляете.

3

Функция считается виртуальной, если она объявлена ​​как virutal или объявлена ​​как виртуальная в любом из ее базовых классов (при вызове с помощью указателя или ссылки).

0

Ожидается поведение в последнем случае. Вы используете ссылки на объект типа Third. Таким образом, виртуальная функция этого класса вызывается во всех трех вызовах. Вы удалили объявление функции в классе Second, но cvlass наследует эту функцию из класса First. Он не отменяет его.

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