Какова первая (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? Но это только догадка.