虚拟继承不破坏静态组合?

Let*_*_Be 5 c++ virtual-inheritance

我在过去5年的工作中假设虚拟继承打破了静态组合.

但是现在我发现,静态组合仍然保持不变,只有关于正确实例位置的附加信息.这是正确的吗?

Wol*_*ngP 21

非虚拟继承中的数据布局:

class Point2d {
    int x_, y_;
};

class Point3d : public Point2d {
    int z_;
};
Run Code Online (Sandbox Code Playgroud)

的Point2D:

+--------------+
| int x_       |
+--------------+
| int y_       |
+--------------+
Run Code Online (Sandbox Code Playgroud)

三维点:

+--------------+   --+
| int x_       |     |
+--------------+     +-- Point2d subobject
| int y_       |     |
+--------------+   --+
| int z_       |
+--------------+
Run Code Online (Sandbox Code Playgroud)

Point3d静态地由Point2d和Point3d的成员组成.

在虚拟继承下

在对象内部使用偏移量变量实现.

class Point3d : public virtual Point2d {
    int z_;
};
Run Code Online (Sandbox Code Playgroud)

三维点:

+-----------------+
| int z_          |
+-----------------+
| Point2d* _vbase |   --> offset to Point2d subobject (2 in this case)
+-----------------+   --+
| int x_          |     |
+-----------------+     +-- Point2d subobject
| int y_          |     |
+-----------------+   --+
Run Code Online (Sandbox Code Playgroud)

Point3d* point3d->x_在此上下文中的访问将被转换为(C++ Pseudocode):

(static_cast<Point2d*>(point3d) + point3d->_vbase)->x_
Run Code Online (Sandbox Code Playgroud)

请注意,在vtable中有不同的方法来实现虚拟继承,例如偏移指针,这只是实现虚拟继承的一种方法.我选择了这个,因为通过vtables的间接需要更多的ascii绘图.

虚拟继承在这里没有任何好处,我希望(正如@Matthieu在评论中指出的)编译器优化这个类,以便它的内部数据布局与非虚拟继承中的相同.虚继承仅在多继承中有用(参见Vertex3d下面的类).

这在多重继承中看起来如何?

 class Vertex : virtual Point2d {
     Vertex* next_;
 };

 class Vertex3d : public Point3d, public Vertex {
 };
Run Code Online (Sandbox Code Playgroud)

顶点:

+-----------------+
| Vertex* next_   |
+-----------------+
| Point2d* _vbase |   --> offset of Point2d subobject (2 in this case)
+-----------------+   --+
| int x_          |     |
+-----------------+     +-- Point2d subobject
| int y_          |     |
+-----------------+   --+
Run Code Online (Sandbox Code Playgroud)

Vertex3d:

+------------------+   --+
| int z_           |     |
+------------------+     +-- Point3d subobject
| Point2d* _vbase1 |     |--> offset to Point2d subobject (4 in this case)
+------------------+   --+
| Vertex* next_    |     |
+------------------+     +-- Vertex subobject 
| Point2d* _vbase2 |     |--> offset to Point2d subobject (2 in this case)
+------------------+   --+
| int x_           |     |
+------------------+     +-- shared Point2d subobject
| int y_           |     |   both Point3d and Vertex point to this 
+------------------+   --+   single copy of Point2d
Run Code Online (Sandbox Code Playgroud)

在虚拟多重继承两个基类VertexPoint3d共享基地Point2dVertex3d.非虚拟继承成员像往常一样布局.

虚拟多重继承的要点是所有后代Point3dVertex将共享一个副本Point2d.如果没有虚拟多重继承(="普通"多重继承),Point3d子对象和Vertex子对象都Vertex3d将拥有自己的副本Point2d:

Vertex3d没有虚拟多重继承的布局:

+------------------+   --+
| int z_           |     |
+------------------+     +-- Point3d subobject --+
| int x_           |     |                       |
+------------------+     |                       +-- Point2d subobject
| int y_           |     |                       |   of Point3d
+------------------+   --+                     --+
| Vertex* next_    |     |
+------------------+     +-- Vertex subobject  --+
| int x_           |     |                       |
+------------------+     |                       +-- Point2d subobject
| int y_           |     |                       |   of Vertex
+------------------+   --+                     --+
Run Code Online (Sandbox Code Playgroud)

参考文献:

  • Lippman:在C++对象模型中.第3章