Указатель на подобъект базового класса. Какая версия виртуальной функции вызывается?

В dynamic binding вызов функции привязан к реализации функции в зависимости от типа объекта, на который указывает указатель.

Предположим, у нас есть следующий код:

base *bptr = new derived;
bptr->func();

Пусть функция func объявлена ​​виртуальной в базовом классе. Затем версия виртуальной функции func производного класса будет вызываться во время выполнения из-за динамического связывания.

Я понимаю вышеизложенную концепцию.

Но меня смутила следующая концепция, которую я изучил после изучения вышеуказанной концепции.

В приведенном выше фрагменте кода указатель на объект производного класса неявно преобразуется в указатель на объект базового класса. Тогда bptr будет фактически указывать на подобъект базового класса объекта производного класса, а не указывать на объект производного класса.

Поскольку указатель базового класса bptr указывает на подобъект базового класса, не следует ли во время выполнения вызывать версию виртуальной функции func базового класса?


person nitin_cherian    schedule 27.01.2012    source источник


Ответы (3)


Похоже, вы не понимаете, что на самом деле означает динамическая привязка. Это означает, что даже если указатель (статически) ссылается на базовый подобъект, вызов будет направлен на (динамический) тип полного объекта.

Обычная реализация осуществляется с помощью таблицы виртуальных функций. Базовый подобъект будет хранить в качестве скрытого члена указатель на таблицу виртуальных функций фактического полного типа, к которому он принадлежит. Все вызовы виртуальных функций (для которых динамическая диспетчеризация не отключена) направляются через этот дополнительный уровень косвенности, гарантируя, что будут вызваны окончательные переопределения.

Что касается специфики управления этой таблицей и скрытым указателем, компилятор строит электронные таблицы для каждого типа с виртуальными функциями и внедряет код в различные конструкторы для соответствующего обновления указателей. Таким образом, при построении базового подобъекта указатель ссылается на базовую виртуальную таблицу, но перед входом в производный конструктор внедренный код обновит указатель (в базе), чтобы он ссылался на производную виртуальную таблицу.

person David Rodríguez - dribeas    schedule 27.01.2012
comment
Дэвид: Значит, и vptr объекта производного класса, и vptr его подобъекта базового класса будут указывать на производный класс VTABLE? - person nitin_cherian; 27.01.2012
comment
@Linux - vptr будет указывать на vtable того типа, которым на самом деле является объект. Указатель, который вы используете для указания на объект, здесь не имеет значения. - person Bo Persson; 27.01.2012
comment
@LinuxPenseur: если для простоты предположить, что производный тип не объявляет никакой новой виртуальной функции, тогда в базовом подобъекте будет храниться единственный указатель, который указывает на производную виртуальную таблицу. - person David Rodríguez - dribeas; 27.01.2012

Не смущайтесь этим. «Указатель на объект производного класса неявно преобразуется в указатель на объект базового класса». Значение этого утверждения состоит в том, что предположим, что derived имеет некоторый метод derivedOnly(), которого нет в base. Теперь, если вы попробуете bptr->derivedOnly();, это вызовет ошибку, даже если вы действительно ссылаетесь на объект derived.

Итак, bptr действительно является указателем на base.

person AppleGrew    schedule 27.01.2012

В этом примере:

base *bptr = new derived;
bptr->func();

класс base просто каким-то образом используется как интерфейс, чтобы узнать, какие методы можно вызывать, поскольку он указывает на экземпляр производного объекта. Виртуальная таблица (http://en.wikipedia.org/wiki/Virtual_method_table) сделает вызов метода из класса derived.

person Pih    schedule 27.01.2012