Что такое первая запись (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 и принимает неограниченное количество аргументов, я ничего не понимаю. К какой функции соответствует этот указатель функции? и откуда вы это знаете? Mine - это 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)*

Ответ 1

Это указатели смещения к вершине (необходимы для множественного наследования) и указатели typeinfo (RTTI).

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

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

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


Смещение сверху вверх более подробно (по запросу)

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

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

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

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

Ответ 2

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