Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 虚拟继承中派生类的大小_C++_Sizeof_Virtual Inheritance_Memory Layout_Vptr - Fatal编程技术网

C++ 虚拟继承中派生类的大小

C++ 虚拟继承中派生类的大小,c++,sizeof,virtual-inheritance,memory-layout,vptr,C++,Sizeof,Virtual Inheritance,Memory Layout,Vptr,在上面的代码中,为什么ClassD的输出是16。请给我解释清楚这个虚拟继承是如何工作的。当ClassD继承ClassB和ClassC时,将有两个VPTR(一个来自B,一个来自C)。Scott Meyers的“更有效的C++”第24项(各种语言功能的成本)中描述了这种情况。当ClassD继承ClassB和ClassC时,将有两个VPTR(一个来自B,一个来自C)。Scott Meyers的“更有效的C++”第24项(各种语言功能的成本)中描述了这种情况。虚拟继承意味着虚拟基类只存在一次而不是多次。

在上面的代码中,为什么ClassD的输出是16。请给我解释清楚这个虚拟继承是如何工作的。

当ClassD继承ClassB和ClassC时,将有两个VPTR(一个来自B,一个来自C)。Scott Meyers的“更有效的C++”第24项(各种语言功能的成本)中描述了这种情况。

当ClassD继承ClassB和ClassC时,将有两个VPTR(一个来自B,一个来自C)。Scott Meyers的“更有效的C++”第24项(各种语言功能的成本)中描述了这种情况。

虚拟继承意味着虚拟基类只存在一次而不是多次。这就是为什么
ClassA
中的8个字节只在
ClassD
中出现一次。虚拟继承本身需要一定的开销,因此您会得到一个额外的指针。精确的实现和确切的开销不是由C++标准指定的,并且可以根据您创建的层次而变化。

虚拟继承意味着虚拟基类只存在一次而不是多次。这就是为什么

ClassA
中的8个字节只在
ClassD
中出现一次。虚拟继承本身需要一定的开销,因此您会得到一个额外的指针。确切的实现和确切的开销没有由C++标准指定,并且可以根据您创建的层次而变化。 虚拟基类与虚拟函数完全相同:它们的地址(或相对地址,又称偏移量)在编译时是未知的:

size of ClassA = 8
size of ClassB = 12
size of ClassC = 12
size of ClassD = 16
在这里,编译器必须计算
ClassA
基子对象与
ClassB
子对象(或大部分派生对象)的偏移量。有些编译器只是在
ClassB
中有一个指向它的指针;其他人使用vtable,就像用于虚拟函数一样

在这两种情况下,
ClassB
中的开销都是一个指针

ClassC
类似,但vptr将指向
ClassC
vtable,而不是
ClassB
vtable

因此,
ClassD
对象将包含(这不是一个有序列表):

  • 单个
    ClassA
    子对象
  • a
    B类
    科目
  • a
    c类
    科目
因此
ClassD
有两个继承的vptr:from
ClassB
ClassC
。在
ClassD
对象中,两个vptr都将指向一些
ClassD
vtable,但都是相同的
ClassD
vtable:

  • a
    ClassB
    subject指向ClassD vtable中的ClassB,表示
    ClassA
    base与
    ClassB
    base的相对位置
  • ClassC
    主题指向ClassD vtable中的ClassC,表示
    ClassA
    base与
    ClassC
    base的相对位置
可能的优化 我想你的问题是:我们需要两个不同的vptr吗?

从技术上讲,有时可以通过覆盖基类子对象来优化类的大小。这是技术上可行的情况之一:

叠加(或统一)意味着
ClassB
ClassC
将共享同一个vptr:给定
d
一个
ClassD
实例:
d.ClassB::vptr==&d.ClassC::vptr
so
d.ClassB::vptr==d.ClassC::vptr
但是
d.ClassB::vptr==&ClassC\u in_ClassD\u vtable
d.ClassC::vptr==&ClassC\u in_ClassD\u vtable
,因此
ClassD\u vtable中的ClassB\u必须与
ClassC\u统一。在这种特殊情况下,
ClassB\u In_ClassD\u vtable
ClassC\u In_ClassD\u vtable
仅用于描述
ClassA
子对象的偏移量;如果
ClassB
ClassC
子对象在
ClassD
中统一,则这些偏移量也统一,因此可以统一vtables

请注意,这仅在这里是可能的,因为存在完全相似性。如果对
ClassB
ClassC
进行了修改,以便在每个虚拟函数中添加一个虚拟函数,例如这些虚拟函数不等价(因此不可统一),则无法实现vtable的统一

结论 这种优化只在像这样非常简单的情况下才可能实现。这些情况并不典型的C++编程:人们通常使用虚拟基类结合虚拟函数。空基类优化是有用的,因为许多C++习语使用没有数据成员或虚拟函数的基类。OTOH,一个用于虚拟基类特殊用途的微小(一个vptr)空间优化对于现实世界的程序似乎没有用处。

虚拟基类实现 虚拟基类与虚拟函数完全相同:它们的地址(或相对地址,又称偏移量)在编译时是未知的:

size of ClassA = 8
size of ClassB = 12
size of ClassC = 12
size of ClassD = 16
在这里,编译器必须计算
ClassA
基子对象与
ClassB
子对象(或大部分派生对象)的偏移量。有些编译器只是在
ClassB
中有一个指向它的指针;其他人使用vtable,就像用于虚拟函数一样

在这两种情况下,
ClassB
中的开销都是一个指针

ClassC
类似,但vptr将指向
ClassC
vtable,而不是
ClassB
vtable

因此,
ClassD
对象将包含(这不是一个有序列表):

  • 单个
    ClassA
    子对象
  • a
    B类
    科目
  • a
    c类
    科目
因此
ClassD
有两个继承的vptr:from
ClassB
ClassC
。在
ClassD
对象中,两个vptr都将指向一些
ClassD
vtable,但都是相同的
ClassD
vtable:

    void f(ClassB *pb) {
        ClassA *pa = pb;
    }