В C ++ является ли функция автоматически виртуальной, если она переопределяет виртуальную функцию?
-
05-07-2019 - |
Вопрос
Я бы ожидал, что если foo
объявлен в классе D
, но не помеченный как virtual, тогда следующий код вызовет реализацию 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
Решение
Стандарт 10.3.2 (class.virtual) гласит:
Если виртуальная функция-член vf объявлена в классе Base и в производном классе, производном прямо или косвенно от Base, объявлена функция-член vf с тем же именем и тем же списком параметров, что и Base::vf, то Derived ::vf также является виртуальным (независимо от того, объявлено это так или нет) и переопределяет*
[Сноска:Функция с тем же именем, но с другим списком параметров (предложение over) в качестве виртуальной функции не обязательно является виртуальной и не переопределяется.Использование виртуального спецификатора при объявлении переопределяющей функции является законным, но избыточным (имеет пустую семантику).Управление доступом (предложение class.access) не учитывается при определении переопределения.--- конец заметки]
Другие советы
Быстрого ответа может быть нет, но правильный ответ - да
C ++ не знает о сокрытии функций, поэтому переопределяет виртуальную функцию без меток виртуальных ключевых слов, которые также функционируют как виртуальные.
Вы не создаете копию объекта e и не помещаете ее в d. Таким образом, d.foo () следует нормальному полиморфному поведению и вызывает метод производного класса. Метод, объявленный как виртуальный в базовом классе, автоматически становится виртуальным в производном классе.
Вывод (" E ") ведет себя точно так, как можно было бы ожидать.
Причина: Динамический (т. Е. Во время выполнения) тип этой ссылки - E. Вы выполняете статическое преобразование в D, но это, конечно, не меняет фактический тип объекта.
В этом и заключается идея виртуальных методов и динамических распределений: вы видите поведение того типа, для которого вы создали экземпляр, в данном случае это E.