Какова первая (int (*) (...)) 0 запись vtable в выходных данных G++ -fdump-class-hierarchy?

этот код:

class B1{
public:  
  virtual void f1() {}  
};

class D : public B1 {
public:
  void f1() {}
};

int main () {
    B1 *b1 = new B1();
    D  *d  = new D();

    return 0;
}

после компиляции, vtable я получаю с g++ -fdump-class-hierarchy - это:

Vtable for B1
B1::_ZTV2B1: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI2B1)
16    B1::f1


Vtable for D
D::_ZTV1D: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI1D)
16    D::f1

Я не понял, что делают записи, как (int ()(...))0* соответствуют. Конечно, это означает что-то вроде, это функция, которая возвращает int и принимает неограниченное количество аргументов, я ничего не понять. Какой функции соответствует указатель этой функции? и откуда ты это знаешь? Мой 64 бит машина.

второй указатель функции имеет адрес, связанный в конце?? Кому это соответствует?

редактировать

компилятор, который я использую, - g++:

g++ -v
Using built-in specs.
Target: x86_64-suse-linux
Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.4 --enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --disable-libmudflap --with-slibdir=/lib64 --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --program-suffix=-4.4 --enable-linux-futex --without-system-libunwind --with-arch-32=i586 --with-tune=generic --build=x86_64-suse-linux
Thread model: posix
*gcc version 4.4.1 [gcc-4_4-branch revision 150839] (SUSE Linux)*

2 ответов


это указатели offset-to-top (необходимые для множественного наследования) и TypeInfo (RTTI).

С Itanium ABI (вы не используете компилятор Itanium, но их описание этого действительно хорошо):

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

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


Offset-to-top более подробно (by запрос)

предположим, у вас есть производный класс D это происходит от базового класса,B1. Что происходит, когда вы пытаетесь бросить D экземпляра типа B1? Поскольку функции B1 объект ничего не знает о D, часть D vtable также должен быть допустимым B1 vtable. Это достаточно просто - просто сделать начало D vtable выглядит как B1 vtable и добавьте любые дополнительные записи, которые нам нужны после этого. Функции ожидая B1 будет счастлив, потому что они не будут использовать какую-либо часть vtable за пределами того, что они ожидают для B1.

однако, что произойдет, если D теперь и происходит от B2? Указатель на D vtable не может быть и действительный B1 vtable и действительный B2 таблицы vtable! Компилятор решает это, добавляя отдельный B2 vtable до конца нашего объединенного D/B1 таблицы vtable, и настраивает указатель vtable вручную, когда мы пытаемся отлить из D до B2.

, это приводит к новой проблеме - что происходит, когда мы пытаемся бросить назад С B2 до D? Компилятор не может просто настроить указатель vtable назад на ту же величину, что и ранее, потому что на самом деле он не знаю что это B2 объект мы даем это типа D! Особенно, dynamic_cast<D>() должны быть в состоянии сказать, является ли наш объект или нет типа D. Для этого ему необходимо получить доступ к RTTI объекта и для это, он должен знать, где находится начало vtable исходного объекта. Это цель значения offset-to-top-оно дает нам смещение к началу vtable исходного объекта, мы получаем RTTI нашего объекта, и мстительный бог c++ позволяет нашим культурам расти для другого сезон.

на этой странице имеет несколько хороших примеров макетов vtable (под таблицы 1С). Обратите внимание, что они немного сложнее из-за использования виртуальное наследование, который добавляет дополнительное смещение к vtable каждого дочернего класса.


может быть, первая запись предназначена для виртуального деструктора, а вторая-для поддержки RTTI? Но это только догадка.