如何解决g ++ -fdump-class-hierarchy输出中的第一个int*…0 vtable条目是什么?
| 对于此代码: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;
}
编译后,使用g++ -fdump-class-hierarchy
得到的vtable是:
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 --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)*
解决方法
这些是顶部偏移量(需要多重继承)和typeinfo(RTTI)指针。
从Itanium ABI(您没有使用Itanium编译器,但是他们对此的描述确实不错):
顶部偏移量将对象从指向该虚拟表的虚拟表指针的对象内位置到对象顶部的位移保持为ptrdiff_t。它总是存在。偏移量提供了一种使用虚拟表指针从任何基础子对象中查找对象顶部的方法。这对于dynamic_cast尤其必要。
(在完整的对象虚拟表中,因此在其所有主基本虚拟表中,此偏移量的值为零。[...])
typeinfo指针指向用于RTTI的typeinfo对象。它总是存在。给定类的每个虚拟表中的所有条目都必须指向相同的typeinfo对象。 typeinfo相等性的正确实现是检查指针的相等性,除了指向不完整类型的指针(直接或间接)之外。 typeinfo指针对于多态类(即具有虚函数的类)是有效的指针,对于非多态类则为零。
更详细的偏移量(根据要求)
假设您有一个派生类
D
,它是从基类B1
派生的。当您尝试将D
实例强制转换为B1
时会发生什么?由于采用B1
对象的函数对D
一无所知,因此D
vtable的一部分也必须是有效的B1
vtable。这很容易-只需使D
vtable的开始看起来像B1
vtable,然后添加我们需要的所有其他条目。期望B1
的函数将很高兴,因为它们不会使用vtable超出beyond5 beyond所期望的任何部分。
但是,如果现在ѭ4又也来自ѭ17,会发生什么呢?指向D
vtable的指针不能同时是有效的B1
vtable和有效的B2
vtable!编译器通过在合并的D/B1
vtable的末尾附加一个单独的B2
vtable来解决此问题,并在我们尝试将D
转换为B2
时手动调整vtable-pointer。
但是,这带来了一个新问题-当我们尝试从ѭ17退回到ѭ4时会发生什么?编译器不能只向后调整vtable-pointer使其达到与先前调整指针相同的数量,因为编译器实际上不确定我们要提供的B2
对象的类型为D
!特别地,dynamic_cast<D>()
必须能够判断我们的对象是否为D
类型。为此,它需要访问对象的RTTI,为此,它需要知道原始对象的vtable的开始位置。这是top-to-top值的目的-它使我们向原始对象的vtable的起始位置偏移,获得对象的RTTI,而C ++的复仇之神使我们的作物得以生长再换一个季节
该页面有一些很好的vtable布局示例(在表1c下)。请注意,由于使用了虚拟继承,因此它们稍微复杂一些,这会为每个子类的vtable增加一个额外的偏移量。,也许第一个条目用于虚拟析构函数,第二个条目用于RTTI支持?但这只是一个猜测。版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。