Я использую VS 2013 и пытаюсь увидеть, как vptr и vftable работают на уровне объектов. Итак, у меня есть следующие классы:
#include<iostream>
using namespace std;
class baseClass
{
public:
void nonVirtualFunc() {}
virtual void virtualNonOverriddenFunc() {}
virtual void virtualOverriddenFunc() {}
};
class derivedClass : public baseClass
{
public:
virtual void virtualOverriddenFunc() {}
virtual void derivedClassOnlyVirtualFunc() { cout << "derivedClass" << endl; }
};int main(int argc, char** argv) {
derivedClass derivedClassObj2;
cout << "Size of derivedClassObj: " << sizeof(derivedClassObj2) << endl;
return 0;
}
И вот что я вижу при отладке:
Теоретически должно быть ДВА вптр. Один для vftable baseClass и один для производного класса для отслеживания недавно добавленного производного класса ClassCnlyVirtualFunc ().
Но, как вы видите, существует только один vptr / vftable. Но механизм работает отлично.
Я подумал, что есть второй vptr, который я не вижу в окне часов, поэтому я распечатал размер объекта. Это 4 байта, указывающих, что присутствует только один указатель.
Так как это работает с недавно добавленный виртуальная функция?
В соответствии с этот должно быть два вптр.
РЕДАКТИРОВАТЬ: Я проверил содержимое памяти vftable, как предложил Серж, и там действительно три записи.
По некоторым причинам это не обнаруживается в отладчике.
Приветствия.
Реализация vtable зависит от компилятора. Размер объекта (4 байта) показывает, что виртуальная таблица не реплицируется в объекте, поскольку 4 байта — это всего лишь один указатель. Мое понимание таково:
_vfptr
является атрибутом класса предка, отладчик показывает его под классом предка, и как таковой показывает только методы, определенные в этом классеНо наверняка реальная _vtable содержит запись для других виртуальных методов … после записей, отображаемых отладчиком!
(*) Все становится сложнее, когда вы думаете о внутренней организации _vfptr
массив. На самом деле, это можно рассматривать как содержащий копии из всех таблиц классов предков. Здесь 2 первые записи derivedClass
соответствуют vtable из baseClass
, Но если вы откроете объем памяти окно и проверьте, что находится по адресу _vfptr (0x00d9ba68
в вашем примере) перед нулевой записью вы должны увидеть третью запись (по крайней мере, так показывает мой MSVC Express 2008). Эта третья запись соответствует функции derivedClassOnlyVirtualFunc
но не показывается отладчиком, как я сказал выше.