Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
165 views
in Technique[技术] by (71.8m points)

c++ - Virtual inheritance doesn't break static composition?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...