本文介绍了虚拟继承不会打破静态组合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



但是现在我发现,静态组合仍然保持,只有有关正确实例位置的附加信息。

解决方案

非虚拟数据布局继承:



  class Point2d {
int x_,y_;
};

class Point3d:public Point2d {
int z_;
};



Point2d:



  + -------------- + 
| int x_ |
+ -------------- +
| int y_ |
+ -------------- +



Point3d :



  + -------------- +  -  + 
| int x_ | |
+ -------------- + + - Point2d子对象
| int y_ | |
+ -------------- + - +
| int Z_ |
+ -------------- +


在虚拟继承下



使用偏移变量对象。

 类Point3d:public virtual Point2d {
int z_;
};



Point3d:



  + ----------------- + 
| int z_ |
+ ----------------- +
| Point2d * _vbase | - >偏移到Point2d子对象(在这种情况下为2)
+ ----------------- + - +
| int x_ | |
+ ----------------- + + - Point2d子对象
| int y_ | |
+ ----------------- + - +

在此上下文中访问 Point3d * point3d-> x _ 将被翻译为(C ++ Pseudocode):

 (static_cast< Point2d *>(point3d)+ point3d-> _vbase) - > x_ 

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



虚拟继承在这里没有好处,我期望(作为@Matthieu注释)以优化此类,使其内部数据布局与非虚拟继承中的相同。虚拟继承仅在多重继承中是有益的(见下面的 Vertex3d 类)。



继承?



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

class Vertex3d:public Point3d,public Vertex {
};



顶点:



  + ----------------- + 
|顶点* next_ |
+ ----------------- +
| Point2d * _vbase | - > Point2d子对象的偏移量(在这种情况下为2)
+ ----------------- + - +
| int x_ | |
+ ----------------- + + - Point2d子对象
| int y_ | |
+ ----------------- + - +



Vertex3d:



  + ------------------ +  -  + 
| int z_ | |
+ ------------------ + + - Point3d子对象
| Point2d * _vbase1 | | - >偏移到Point2d子对象(在这种情况下为4)
+ ------------------ + - +
|顶点* next_ | |
+ ------------------ + + - 顶点子对象
| Point2d * _vbase2 | | - >偏移到Point2d子对象(在这种情况下为2)
+ ------------------ + - +
| int x_ | |
+ ------------------ + + - 共享Point2d子对象
| int y_ | | Point3d和Vertex都指向这个
+ ------------------ + - + Point2d的单个副本

在虚拟多重继承中,两个基类顶点 Point3d 共享 Vertex3d 中的基础 Point2d



虚拟多重继承的观点是所有后代 Point3d 顶点将共享 Point2d 的一个副本。没有虚拟多重继承(=普通多重继承) Point3d 子对象和顶点子对象 Vertex3d 会有自己的 Point2d 副本:



code> Vertex3d 无虚多重继承:



  + ------- ----------- +  -  + 
| int z_ | |
+ ------------------ + + - Point3d子对象 - +
| int x_ | | |
+ ------------------ + | + - Point2d subobject
| int y_ | | | of Point3d
+ ------------------ + - + - +
|顶点* next_ | |
+ ------------------ + + - 顶点子对象 - +
| int x_ | | |
+ ------------------ + | + - Point2d subobject
| int y_ | | | of Vertex
+ ------------------ + - + - +



参考文献:




  • Lippman:第3章


I was working the last 5 years with the assumption that virtual inheritance breaks static composition.

But now I discovered, that static composition is still maintained, there is just additional information about the location of the correct instance. Is this right?

解决方案

Data Layout in non-virtual Inheritance:

class Point2d {
    int x_, y_;
};

class Point3d : public Point2d {
    int z_;
};

Point2d:

+--------------+
| int x_       |
+--------------+
| int y_       |
+--------------+

Point3d:

+--------------+   --+
| int x_       |     |
+--------------+     +-- Point2d subobject
| int y_       |     |
+--------------+   --+
| int z_       |
+--------------+

Point3d is statically composed of Point2d and the member of Point3d.

Under virtual inheritance

Implemented with an offset variable inside the object.

class Point3d : public virtual Point2d {
    int z_;
};

Point3d:

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

Accessing Point3d* point3d->x_ in this context will be translated to (C++ Pseudocode):

(static_cast<Point2d*>(point3d) + point3d->_vbase)->x_

Note that there are different ways to implement virtual inheritance like offset pointers inside the vtable, this is just one way to implement virtual inheritance. I chose this one because indirection via vtables would require more ascii drawing.

Virtual inheritance has no benefit here and I would expect (as @Matthieu noted in the comments) a compiler to optimize this class so that it's internal data layout is the same as in non-virtual inheritance. Virtual inheritance is only beneficial in multiple inheritance (see Vertex3d class below).

How does this look like in multiple inheritance?

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

 class Vertex3d : public Point3d, public Vertex {
 };

Vertex:

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

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

In virtual multiple inheritance both base classes Vertex and Point3d share the base Point2d in Vertex3d. non-virtual inherited members are layed out as usual.

The point of virtual multiple inheritance is that all descendants of Point3d and Vertex will share one copy of Point2d. Without virtual multiple inheritance (= "ordinary" multiple inheritance) both the Point3d subobject and the Vertex subobject of Vertex3d would have its own copy of Point2d:

Layout of Vertex3d without virtual multiple inheritance:

+------------------+   --+
| int z_           |     |
+------------------+     +-- Point3d subobject --+
| int x_           |     |                       |
+------------------+     |                       +-- Point2d subobject
| int y_           |     |                       |   of Point3d
+------------------+   --+                     --+
| Vertex* next_    |     |
+------------------+     +-- Vertex subobject  --+
| int x_           |     |                       |
+------------------+     |                       +-- Point2d subobject
| int y_           |     |                       |   of Vertex
+------------------+   --+                     --+

References:

  • Lippman: Inside the C++ Object Model. Chapter 3

这篇关于虚拟继承不会打破静态组合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 10:59