Virtual Class Inheritance in C++
Java has notions of both class inheritance and interface inheritance, where interfaces are only sets of methods. To mimic this very useful behavior in C++ I often define classes with only a single method, such as
class Point; struct PointSet { virtual bool contains (const Point & const) const = 0; }; class Point { ... public: inline bool in (const PointSet & point_set) const { return point_set.contains(*this); } ... };
so that when defining objects which “are”, among other things, sets of points, they can inherit as so:
class Environment : public PointSet { ... public: virtual bool contains (const Point & point) const { ... } ... };
In complicated class hierarchies, it can be useful to aggregate such abstract interface classes, e.g.,
struct MetricSpace : public PointSet { ... }; struct VectorSpace : public PointSet { ... }; struct BanachSpace : public MetricSpace, public VectorSpace { ... };
But oops, BanachSpace is now a PointSet in two distinct ways, i.e. via VectorSpace::contains
and via MetricSpace::contains
. To avoid this so called “diamond problem”
PointSet PointSet PointSet / \ | | VectorSpace MetricSpace vs VectorSpace MetricSpace \ / \ / BanachSpace BanachSpace
C++ designers invented virtual inheritance which allows a unique inheritance of each interface-like method, so that in
struct MetricSpace : public virtual PointSet { ... }; struct VectorSpace : public virutal PointSet { ... }; struct BanachSpace : public virtual MetricSpace, public virtual VectorSpace { ... };
References
BanachSpace::contains
is unique.
C++0x
Gcc 4.4 and later support nice C++0x features like hash tables via std::unordered_map
and auto
typed variables, as in
std::unordered_map< std::pair, std::vector<std::pair > > widgets = get_widgets(); for (auto i = widgets.begin(); i != widgets.end(); ++i) { std::swap(i->second.first, i->second.second); }
The new standard also allows variadic initializer lists with a small speed penalty.
My favorite features are:
February 13, 2011 at 11:07 pm
Is the only purpose of virtual inheritance to solve the diamond problem?
If so, then it seems like the C++ language could have been made so that the compiler automatically checks for ambiguity when calling inherited functions. Apparently in Python all functions are virtual. This makes me wonder whether there is some limitation or speed reason for not having it automatic in C++…
February 14, 2011 at 4:22 pm
I think we have confused virtual inheritance of classes with virtual inheritance of methods.
Yes there is a speed penalty to virtually inheriting methods in C++: it requires run-time method lookup in the vtable, and hence additionally prevents inlining.
No the purpose of virtual methods is not related to the diamond problem. The purpose of virtual methods is to specify an abstract interface (a set of methods) in a base class, and allow derived classes to implement these methods. This allows extension of a class hierarchy after compile-time.
Virtual inheritance of classes does address the diamond problem.
February 14, 2011 at 10:15 pm
I’m sorry the second paragraph of my response was confusing. I do understand that virtual inheritance of classes is different than a virtual function, but I do not understand (1) whether the only purpose of virtual inheritance is to solve the diamond problem and (2) why is not all inheritance virtual?