Подтвердить что ты не робот

В С++ функция является автоматически виртуальной, если она переопределяет виртуальную функцию?

Я бы ожидал, что если 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
4b9b3361

Ответ 1

Стандарт 10.3.2 (class.virtual) говорит:

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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