请考虑以下代码:
#include <iostream>
#include <typeinfo>
#include <type_traits>
using namespace std;
struct A { int data; };
struct B1 : A {};
struct B2 : virtual A {};
struct Base1 : virtual A {};
struct Base2 : virtual A {};
struct Derived : Base1, Base2 {};
int main() {
cout << sizeof(B1) << endl;
cout << sizeof(B2) << endl;
cout << sizeof(Derived) << endl;
cout << std::is_polymorphic<B1>::value << endl;
cout << std::is_polymorphic<B2>::value << endl;
cout << std::is_polymorphic<Derived>::value << endl;
return 0;
}
在我的系统上打印
4
8
12
0
0
0
这意味着这些类都不是多态的。但是,B1和B2的大小完全不同于指针的大小,这可能是指向vtable的指针。我用-fdump-class-hierarchy
运行了gcc并得到了:
Vtable for B2
B2::_ZTV2B2: 3u entries
0 4u
4 (int (*)(...))0
8 (int (*)(...))(& _ZTI2B2)
VTT for B2
B2::_ZTT2B2: 1u entries
0 ((& B2::_ZTV2B2) + 12u)
Class B2
size=8 align=4
base size=4 base align=4
B2 (0x0x3ca5400) 0 nearly-empty
vptridx=0u vptr=((& B2::_ZTV2B2) + 12u)
A (0x0x3c972d8) 4 virtual
vbaseoffset=-12
这是一个问题:什么是多态类? 'vtable'是否意味着'具有多态性并具有RTTI',反之亦然?如果没有,为什么它必须至少有一个虚拟函数是多态的,如果它仍然有vtable?
看起来多态类的定义不同于'具有vtable的类',因为正如我们上面所看到的,B2不是多态的,而是有一个vtable,并且我认为应该有一个RTTI。在this文档中,它清楚地表明“多态 - 即至少有一个虚函数。(这是允许生成的调度代码在类上使用RTTI所必需的。)”。
答案 0 :(得分:6)
您在此处缺少详细信息:虚拟表是实施细节。结果:
因此,是我认识的编译器(MSVC以及跟随Itanium ABI的编译器,如gcc,icc和Clang)将使用虚拟表来提供dynamic_cast
工作所需的RTTI在存在虚拟基础的情况下......并且这与类是否具有多态性无关。
但是,在切线上,首选组合超过继承意味着如果没有可以覆盖的行为,则没有理由从类继承。
答案 1 :(得分:3)
如果T是一个多态类(即一个声明或类的类) 继承至少一个虚函数),提供成员常量 价值相等。对于任何其他类型,值为false。
由于没有定义虚拟的函数,它将返回false。
详细说明,我们应该区分多态性和vtable。在C ++中,vtables确实需要多态性,但也适用于其他非多态性概念。
我可以尝试解释虚拟继承,当与多重继承一起使用时会创建一个vtable,但this link会做得更好。
答案 2 :(得分:2)
对于那些对继承所提供的VTable的影响感到好奇的人。
以下示例
struct VB{
// virtual int f(){}
};
struct IA:virtual VB{};
int main(int argc, char** argv) {
VB* o = new IA;
IA* iap = dynamic_cast<IA*>(o);
}
将无法编译(g ++ 4.8):
main.cpp:在函数'int main(int,char **)'中:main.cpp:26:34:错误: 不能dynamic_cast'o'('struct VB *'类型)来输入'struct IA *' (源类型不是多态的) IA * iap = dynamic_cast(o);
取消注释int f()
成员会得到所需的结果。