2014-12-01 5 views
-1

Я использую VS 2013 и пытаюсь увидеть, как vptr и vftable работают на уровне объекта. Таким образом, у меня есть следующие классы:Как один vtable отслеживает новые виртуальные функции?

#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; 
} 

И это то, что я вижу при отладке: enter image description here

Теоретически должно быть ДВА vptrs. Один для vftable baseClass и один для производного класса для отслеживания недавно добавленного метода производного класса ClassClassOnlyVirtualFunc().

Но, как вы видите, есть только один vptr/vftable. Но механизм работает отлично.

Я думал, что есть второй vptr, который я не вижу в окне часов, поэтому я распечатал размер объекта. Это 4 байта, что указывает на наличие только одного указателя.

Как это работает с недавно добавленной виртуальной функцией?

Согласно this должно быть два vptrs.

EDIT: Я проверил содержимое памяти vftable, как предложил Серж, и действительно есть три записи. enter image description here По какой-то причине он не отображается в отладчике.

Cheers.

+0

Нет, потому что, когда вы создаете производный объект, записи в таблице vtable заменяются адресами виртуальных функций производных (если их переопределить). Это делается во время построения объекта, который объясняет, почему вы не должны называть виртуальные функции в конструкторах/деструкторах. – Borgleader

+0

Почему в объекте должно быть два?Одного достаточно, производные классы vtable основаны на базовых классах, добавляя дополнительные записи для большего количества виртуальных машин и заменяя другие, чтобы указать на новую реализацию. – Deduplicator

+0

@Borgleader: вызов виртуальных функций в ctors и dtors прекрасен. – Deduplicator

ответ

1

Реализация vtable зависит от компилятора. Размер объекта (4 байта) показывает, что vtable не реплицируется в объекте, так как 4 байта - это всего лишь один указатель. Мое понимание:

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

Но наверняка реальный _vtable содержит запись для других виртуальных методов ... кормовой er записи, отображаемые отладчиком!

(*) Становится все труднее, если вы подумаете о внутренней организации массива _vfptr. Фактически, это можно увидеть как содержащее копии всех классов vtables класса предков. Здесь две первые записи derivedClass соответствуют таблице vtable baseClass. Но если вы откроете окно Memory и изучите, что находится на адресе _vfptr (0x00d9ba68 в вашем примере), вы должны увидеть третью запись перед пустой записью (по крайней мере, это показывает мой MSVC Express 2008). Эта третья запись соответствует функции derivedClassOnlyVirtualFunc, но не показана отладчиком, как я сказал выше.

+0

1. Даже * экзистенция * таблицы vtable (если есть) является деталью реализации. 2. Посмотрите на 'std :: iostream'. По моему счету, он имеет 3 vtables, потому что каждый экземпляр имеет 3 указателя vtable. (О некоторых общих реализациях.) 3. Ни основные типы, ни классы, у которых ни виртуальные базы, ни члены не имеют vtable и vtable-указатель. – Deduplicator

+0

@Serge Спасибо. Я просмотрел содержимое памяти, и, похоже, нет третьей записи. Я обновил исходный вопрос с помощью снимка экрана. – madu

+0

@Serge Вы правы. Есть запись. Я сделал ошибку в коде. Спасибо тебе за это. Странно, почему он не появится. – madu