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?
One more benefit of composition over inheritance is testing scope. Unit testing is easy in composition because we know what all methods we are using from another class. We can mock it up for testing whereas in inheritance we depend heavily on superclass and don't know what all methods of superclass will be used.
Virtual inheritance is used when we are dealing with multiple inheritance but want to prevent multiple instances of same class appearing in inheritance hierarchy. From above example we can see that “A” is inherited two times in D means an object of class “D” will contain two attributes of “a” (D::C::a and D::B::a).
Virtual inheritance is a C++ technique that ensures only one copy of a base class's member variables are inherited by grandchild derived classes.
class Point2d {
int x_, y_;
};
class Point3d : public Point2d {
int z_;
};
+--------------+
| int x_ |
+--------------+
| int y_ |
+--------------+
+--------------+ --+
| int x_ | |
+--------------+ +-- Point2d subobject
| int y_ | |
+--------------+ --+
| int z_ |
+--------------+
Point3d is statically composed of Point2d and the member of Point3d.
Implemented with an offset variable inside the object.
class Point3d : public virtual Point2d {
int z_;
};
+-----------------+
| 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).
class Vertex : virtual Point2d {
Vertex* next_;
};
class Vertex3d : public Point3d, public Vertex {
};
+-----------------+
| Vertex* next_ |
+-----------------+
| Point2d* _vbase | --> offset of Point2d subobject (2 in this case)
+-----------------+ --+
| int x_ | |
+-----------------+ +-- Point2d subobject
| int y_ | |
+-----------------+ --+
+------------------+ --+
| 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
:
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
+------------------+ --+ --+
Objects of classes that use virtual inheritance have a fixed memory layout that is determined in compilation time. Accessing the virtual base however requires a level of indirection since you cannot tell where it is relative to the derived pointer.
See Wikipedia
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With