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