Является ли функция в C ++ автоматически виртуальной, если она переопределяет виртуальную функцию? - PullRequest
20 голосов
/ 10 сентября 2009

Я ожидаю, что если foo объявлен в классе D, но не помечен как виртуальный, то следующий код вызовет реализацию foo в D (независимо от динамического типа d ).

D& d = ...;
d.foo();

Однако в следующей программе это не так. Кто-нибудь может объяснить это? Является ли метод автоматически виртуальным, если он переопределяет виртуальную функцию?

#include <iostream>

using namespace std;

class C {
public:
        virtual void foo() { cout << "C" << endl; }
};

class D : public C {
public:
        void foo() { cout << "D" << endl; }
};

class E : public D {
public:
        void foo() { cout << "E" << endl; }
};

int main(int argc, char **argv)
{
        E& e = *new E;
        D& d = *static_cast<D*>(&e);
        d.foo();
        return 0;
}

Вывод вышеуказанной программы:

E

Ответы [ 4 ]

22 голосов
/ 10 сентября 2009

Стандарт 10.3.2 (class.virtual) гласит:

Если виртуальная функция-член vf объявлена ​​в классе Base и в классе Derived, производном прямо или косвенно из Base, объявляется функция-член vf с тем же именем и тем же списком параметров, что и Base :: vf, тогда Derived :: vf также является виртуальным (независимо от того, объявлено оно или нет) и переопределяет *

[Сноска. Функция с тем же именем, но с другим списком параметров (пункт над) в качестве виртуальной функции не обязательно является виртуальной и не переопределяет. Использование виртуального спецификатора в объявлении переопределяющей функции является законным, но избыточным (имеет пустую семантику). Контроль доступа (пункт class.access) не учитывается при определении переопределения. --- конец foonote]

17 голосов
/ 10 сентября 2009

Быстрый ответ может быть нет, но правильный ответ да

C ++ не знает о сокрытии функций, поэтому переопределяет виртуальную функцию без меток виртуальных ключевых слов, которые также функционируют как виртуальные.

0 голосов
/ 10 сентября 2009

Вывод ("E") ведет себя точно так, как можно было бы ожидать.

Причина: Динамический (т. Е. Во время выполнения) тип этой ссылки - E. Вы выполняете статическое преобразование до D, но это, конечно, не меняет фактический тип объекта.

В этом и заключается идея виртуальных методов и динамических распределений: вы видите поведение того типа, для которого вы создали экземпляр, в данном случае это E.

0 голосов
/ 10 сентября 2009

Вы не создаете ни одной копии объекта e и не помещаете ее в d. Таким образом, d.foo () следует нормальному полиморфному поведению и вызывает метод производного класса. Метод, объявленный как виртуальный в базовом классе, автоматически становится виртуальным в производном классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...