C ++:是一个具有虚拟基础的类但没有虚函数的多态并且具有VTable?

时间:2013-11-24 12:20:30

标签: c++ polymorphism rtti virtual-functions virtual-inheritance

请考虑以下代码:

#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所必需的。)”。

3 个答案:

答案 0 :(得分:6)

您在此处缺少详细信息:虚拟表是实施细节。结果:

  • 标准将多态类定义为可以在多态意义上使用的类:即,可以覆盖行为的地方
  • 编译器使用虚拟表来实现标准规定的某些功能/行为,这些功能/行为恰好包括多态类和虚拟基础。

因此,我认识的编译器(MSVC以及跟随Itanium ABI的编译器,如gcc,icc和Clang)将使用虚拟表来提供dynamic_cast工作所需的RTTI在存在虚拟基础的情况下......并且这与类是否具有多态性无关。

但是,在切线上,首选组合超过继承意味着如果没有可以覆盖的行为,则没有理由从类继承。

答案 1 :(得分:3)

以下是对std::is_polymorphic

的辩护
  

如果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()成员会得到所需的结果。