Я изучаю наследование в C ++ 11 и обнаружил, что если производный класс переопределил имя виртуальной функции, но с другим прототипом, указатель базового класса, назначенный с указателем на производный класс, может получить доступ только кверсия функции базового класса. Производная функция версии недоступна. Интересно, почему это происходит?
class Enemy {
public:
virtual void describe() { std::cout << "Enemy"; }
};
class Dragon : public Enemy {
public:
virtual void describe(int dummy) { std::cout << "Dragon"; }
};
В main
,
Dragon foo;
Enemy* pe = &foo;
pe->describe(); // Enemy
foo.describe(1); // Dragon
pe->describe(1); // no matching function, candidate is Enemy::describe()
Из того, что я знаю о таблицах виртуальных функций, производный объект, на который указывает pe
(т. Е. foo
) должен иметь член vpointer, который указывает на vtable Dragon
. Я также знаю, что переопределение имени функции в производном классе скроет все функции с тем же именем в базовом классе. Таким образом, в vtable Дракона адресом `description 'должна быть функция с параметром int dummy
.
Но оказывается, что pe
может получить доступ к Enemy
версии метода, которая должнабыть скрытымИ pe
не может получить доступ к версии метода Dragon
, которая должна быть в vtable таблицы pe
. Он работает так, как будто используется таблица Enemy
. Почему это происходит?
Обновление : Я думаю, теперь я более или менее понимаю механизмы, стоящие за этим. Вот моя гипотеза:
Поскольку это указатель на Enemy
, программа сначала найдет имя метода в области действия Enemy
. Если имя не найдено, компилятор выдает ошибку. Если он не виртуальный, тогда позвоните. Если он виртуальный, запишите смещение метода в таблицу Enemy
. Затем программа использует это смещение для доступа к нужному методу в vtable целевого объекта.
Если метод корректно переопределен, адрес функции в vtable целевого объекта с этим смещением был бы изменен. В противном случае это будет тот же адрес функции, что и в таблице Enemy
, как в примере.
Поскольку Dragon
describe
с int dummy
- это другой прототип, ондобавлен в vtable Dragon
после оригинального describe
, унаследованного от Enemy. Но к версии int dummy
нельзя получить доступ из Enemy*
, потому что vtable Enemy
даже не имеет этого смещения.
Это правильно?