How does virtual inheritance actually work? - c++

I know about the diamond problem but the thing is - when I google "virtual inheritance" the results mention only the diamond problem. I want to know how it works in general and how is it different from normal inheritance.
I know when a class (normally) inherits from another class it simply contains all its members (fields and methods, leaving aside the access levels). Some of them may be overridden or hidden by new members but they're still there. Inheritance also defines certain relationships between classes in hierarchy which affects casting and polymorphism.
Now how is virtual inheritance different? For instance:
class A
{
public:
int a;
int b;
void fun(int x)
{}
void gun(int x)
{}
};
class B : public A
{
public:
int a;
int c;
void fun(int x)
{}
void hun(int x)
{}
};
class C : virtual public A
{
public:
int a;
int c;
void fun(int x)
{}
void hun(int x)
{}
};
What are the differences between B and C? Are there any other differences that my example doesn't exploit? What does the standard say? Also, if there's a difference between C++03 and C++11 please mention it.

With a single level of inheritance, there's no difference in behaviour.
The difference is when inheriting from multiple base classes, which themselves have a common base class:
struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B,C {};
In this example, with virtual inheritance, D contains just one A sub-object, which its B and C subobjects share; this is the "diamond" pattern:
A
/ \
B C
\ /
D
Without virtual inheritance, it would contain two A sub-objects, and no "diamond":
A A
| |
B C
\ /
D
With or without multiple inheritance, there's still a difference if you have more than one level of inheritance: a virtual base class must be initialised by the most derived class, not by its immediate derived class. This is to avoid the ambiguity in the case of multiple inheritance, where (in the example above) both B and C would otherwise be responsible for initialising the shared A.

Related

Multiple inheritance: usage of skipping 'virtual' keyword and refusing the diamond hierarchy?

I understand how and why do we have to use the virtual keyword to solve the "diamond problem", and create a class hierarchy like this:
A
/ \
/ \
B C
\ /
\ /
D
Code example:
class A { int a; public: A(int a) : a(a) {} };
class B : public virtual A { int b; public: B(int a, int b) : A(a), b(b) {} };
class C : public virtual A { int c; public: C(int a, int c) : A(a), c(c) {} };
class D : public B, public C { public: D(int a, int b, int c) : A(a), B(0, b), C(0, c) {} };
I couldn't find an answer to my question: Why do we have to tell the compiler (using the virtual keyword) that we want to create a "diamond" class hierarchy? Why does the compiler not generate it automatically?
If we don't use virtual, the compiler generates the class hierarchy below:
A A
| |
| |
B C
\ /
\ /
D
Is there any programming situation where the second hierarchy is useful and works?
EDIT (to make my question clear): Why did they want us to use virtual? I suppose, the reason is that they wanted to give an option to us. Any example where the second class hierarchy is the best choice to use?
Consider the case where A is a visitor interface, while B and C implement this interface independently of each other, and need differing visitation behavior.
class A
{
public:
virtual void visit(int) = 0;
};
class B : virtual private A
{
public:
virtual void visit(int) { }
};
class C : virtual private A
{
public:
virtual void visit(int) { }
};
class D : public B, public C { };
// error: virtual function 'A::visit' has more than one final overrider in 'D'
This does not compile. It is desirable and necessary in this case for B and C to retain separate A subobjects. Removing the virtual inheritance in this example allows it to compile.
Is there any programming situation where the second hierarchy is useful and works?
Although there might be, that becomes a less interesting question (in my opinion) after I've answered the other one.
Why do we have to tell the compiler (using the virtual keyword) that we want to create a "diamond" class hierarchy? Why does the compiler not generate it automatically?
No, the compiler cannot generate it automatically. That is why you have to tell the compiler explicitly when you want inheritance to be virtual.
Assuming such automation existed, in order for the compiler to guess that the base A of B should be virtual, it would have to know that A is also the base of C, and that B and C are both bases of D. So, the meaning of the definition of B would depend on the definition of D (which also depends on C. Essentially, all classes that are part of same hierarchy will depend in all other classes in that hierarchy, except the very top base). But some classes of the hierarchy may be defined in completely different translation units that may be compiled at a completely different time than the others. The C++ compiler simply cannot assume that it has knowledge of all classes.
There is one approach that would make this possible: Make all inheritance virtual. However, virtual inheritance has some (small, but non-zero) overhead, so this is not an ideal solution. Also, virtual inheritance makes static_cast to derived type impossible, so such cast would require dynamic_cast which requires Run Time Type Information and there is interest in allowing limited C++ implementations that lack RTTI support.

Provide implementation to pure virtual function through multiple inheriting another class [duplicate]

Say we have a class inheriting from two base classes (multiple inheritance). Base class A is abstract, declaring a pure virtual function foo, the other base class B declares and implements a function foo of the very same signature.
struct A
{
virtual void foo(int i) = 0;
};
struct B
{
virtual void foo(int i) {}
};
struct C : public A, public B {};
I want to use the implementation of foo from base class B in my derived class C. However, if I do not implement the function foo a second time in my derived class C, I cannot instantiate any object of it (it remains abstract). Virtual inheritance does not help here as expected (class A and class B have no common base class).
I wonder if there is a way to "import" the implementation of foo from class B into class C in order not to have to repeat the same code.
Above example is of course contrived. The reason I want implement foo in class B is that I want to derive class D : public B and use class Bs implementation of foo. I know that inheritance is not (primarily) intended for code reuse, but I'd still like to use it in that way.
In java, your sample code works. In C++ it doesn't. A subtle difference between those languages.
Your best option in C++ is to define C::foo() by forwarding to B::foo():
struct C : public A, public B
{
virtual void foo(int i) { B::foo(i); }
};

Where is the "virtual" keyword necessary in a complex multiple inheritance hierarchy?

I understand the basics of C++ virtual inheritance. However, I'm confused about where exactly I need to use the virtual keyword with a complex class hierarchy. For example, suppose I have the following classes:
A
/ \
B C
/ \ / \
D E F
\ / \ /
G H
\ /
I
If I want to ensure that none of the classes appear more than once in any of the subclasses, which base classes need to be marked virtual? All of them? Or is it sufficient to use it only on those classes that derive directly from a class that may otherwise have multiple instances (i.e. B, C, D, E and F; and G and H (but only with the base class E, not with the base classes D and F))?
I toyed a program together which could help you to study the intricacies of virtual bases. It prints the class hierarchy under I as a digraph suitable for graphiviz ( http://www.graphviz.org/ ). There's a counter for each instance which helps you to understand the construction order as well. Here's the programm:
#include <stdio.h>
int counter=0;
#define CONN2(N,X,Y)\
int id; N() { id=counter++; }\
void conn() \
{\
printf("%s_%d->%s_%d\n",#N,this->id,#X,((X*)this)->id); \
printf("%s_%d->%s_%d\n",#N,this->id,#Y,((Y*)this)->id); \
X::conn(); \
Y::conn();\
}
#define CONN1(N,X)\
int id; N() { id=counter++; }\
void conn() \
{\
printf("%s_%d->%s_%d\n",#N,this->id,#X,((X*)this)->id); \
X::conn(); \
}
struct A { int id; A() { id=counter++; } void conn() {} };
struct B : A { CONN1(B,A) };
struct C : A { CONN1(C,A) };
struct D : B { CONN1(D,B) };
struct E : B,C { CONN2(E,B,C) };
struct F : C { CONN1(F,C) };
struct G : D,E { CONN2(G,D,E) };
struct H : E,F { CONN2(H,E,F) };
struct I : G,H { CONN2(I,G,H) };
int main()
{
printf("digraph inh {\n");
I i;
i.conn();
printf("}\n");
}
If I run this (g++ base.cc ; ./a.out >h.dot ; dot -Tpng -o o.png h.dot ; display o.png), I get the typical non-virtual base tree:
Adding enough virtualness...
struct B : virtual A { CONN1(B,A) };
struct C : virtual A { CONN1(C,A) };
struct D : virtual B { CONN1(D,B) };
struct E : virtual B, virtual C { CONN2(E,B,C) };
struct F : virtual C { CONN1(F,C) };
struct G : D, virtual E { CONN2(G,D,E) };
struct H : virtual E,F { CONN2(H,E,F) };
struct I : G,H { CONN2(I,G,H) };
..results in the diamond shape (look at the numbers to learn the construction order!!)
But if you make all bases virtual:
struct A { int id; A() { id=counter++; } void conn() {} };
struct B : virtual A { CONN1(B,A) };
struct C : virtual A { CONN1(C,A) };
struct D : virtual B { CONN1(D,B) };
struct E : virtual B, virtual C { CONN2(E,B,C) };
struct F : virtual C { CONN1(F,C) };
struct G : virtual D, virtual E { CONN2(G,D,E) };
struct H : virtual E, virtual F { CONN2(H,E,F) };
struct I : virtual G,virtual H { CONN2(I,G,H) };
You get a diamond with a different initialization order:
Have fun!
You have to specify virtual inheritance when inheriting from any of A, B, C, and E classes (that are at the top of a diamond).
class A;
class B: virtual A;
class C: virtual A;
class D: virtual B;
class E: virtual B, virtual C;
class F: virtual C;
class G: D, virtual E;
class H: virtual E, F;
class I: G, H;
My personal suggestion would be to start at B and C : virtual A, and then keep adding until the compiler stops complaining.
In reality, I'd say that B and C : virtual A, G and H : virtual E, and E : virtual B and C. All the other inheritance links can be normal inheritance. This monstrosity would take like six decades to make a virtual call, though.
If you want to make sure that an object of the top class in the hierarchy (I in your case) contains exactly one subobject of each parent class, you have to find all classes in your hierarchy that have more than one superclass and make these classes virtual bases of their superclasses. That's it.
In your case classes A, B, C and E have to become virtual base classes every time you inherit from them in this hierarchy.
Classes D, F, G and H don't have to become virtual base classes.
If you want to have only one "physical" instance of each type for each instance of each type (only one A, only one B etc.) You'll just have to use virtual inheritance each time you use inheritance.
If you want separate instances of one of the types, use normal inheritance.
Edited: I thought A was the most derived class ;)
#Luther's answer really cool, but back to the original question:
You NEED to use virtual inheritance when inheriting from any class from which at least one other class inherits in the inheritance hierarchy (in Luther's diagrams it means at least two arrows point to the class).
Here it's unnecessary before D, F, G and H because only one class derives from them (and none derives from I at the moment).
However, if you don't know beforehand whether or not another class will inherit from your base class, you can add in virtual as a precaution. For example it's recommended for an Exception class to inherit virtually from std::exception by no other than Stroustrup himself.
As Luther has noted, it modifies the instantiation order (and has a slight effect on performances) but I would consider any design relying on the construction order to be wrong to begin with. And just as a precision: you still have the guarantees that base classes are initialized before any attribute of the derived class, and therefore before the execution of the derived's constructor body.
On thing to keep in mind is C++ keeps a table of the inheritance. The more you add virtual classes, the longer will be compilation time (linkage) and the heavier would be the runtime.
In general, if one can avoid virtual class, you can replace by some templates or try to decouple in some way.

Multiple inheritance + virtual function mess

I have a diamond multiple inheritance scenario like this:
A
/ \
B C
\ /
D
The common parent, A, defines a virtual function fn().
Is it possible for both B and C to define fn()?
If it is, then the next question is - can D access both B and C's fn() without disambiguation? I'm assuming there is some syntax for this..
And is it possible for D to do that without knowing specifically who are B and C? B and C can be replaces by some other classes and I want the code in D to be generic.
What I'm trying to do is to have D somehow enumerate all of the instances of fn() it has in its ancestry. Is this possible in some other means that virtual functions?
Unless you overwrite fn again in D, no it is not possible. Because there is no final overrider in a D object: Both C and B override A::fn. You have several options:
Drop either C::fn or B::fn. Then, the one that still overrides A::fn has the final overrider.
Place a final overrider in D. Then, that one overrides A::fn aswell as fn in C and B.
For example the following results in a compile time error:
#include <iostream>
class A {
public:
virtual void fn() { }
};
class B : public virtual A {
public:
virtual void fn() { }
};
class C : public virtual A {
public:
virtual void fn() { }
};
// does not override fn!!
class D : public B, public C {
public:
virtual void doit() {
B::fn();
C::fn();
}
};
int main(int argc, char **argv) {
D d;
d.doit();
return 0;
}
You can, however derive non-virtual from A in C and B, but then you have no diamond inheritance anymore. That is, each data-member in A appears twice in B and C because you have two A base-class sub-objects in an D object. I would recommend you to rethink that design. Try to eliminate double-objects like that that require virtual inheritance. It often cause such kind of conflicting situations.
A case very similar to this is when you want to override a specific function. Imagine you have a virtual function with the same name in B and C (now without a common base A). And in D you want to override each function but give different behavior to each. Depending whether you call the function with a B pointer or C pointer, you have the different behavior. Multiple Inheritance Part III by Herb Sutter describes a good way of doing that. It might help you decide on your design.
First question, yes, B and C can define fn() as a virtual function.
Second, D can of course access B::fn() and C::fn() by using the scope operator ::
Third question: D must at least know B and C, since you have to define them on the inheritance list. You can use templates to let the types of B and C open:
class A
{
public:
virtual ~A() {}
virtual void fn() = 0;
};
class B: public A
{
public:
virtual ~B() {}
virtual void fn(){ std::cout << "B::fn()" << std::endl; }
};
class C: public A
{
public:
virtual ~C() {}
virtual void fn(){ std::cout << "C::fn()" << std::endl; }
};
template <typename TypeB, typename TypeC>
class D: public TypeB, public TypeC
{
public:
void Do()
{
static_cast<TypeB*>(this)->fn();
static_cast<TypeC*>(this)->fn();
}
};
typedef D<B, C> DInst;
DInst d;
d.Do();
About the wish to automatically enumerate all fn() functions of all classes that D inherits from: I'm not sure if that is possible without resorting to MPL. At least you can extend my example above with versions that deal with 3 and more template parameters, but I guess there is an upper (internal compiler-)limit of number of class template parameters.
You cannot enumerate the definitions of fn() in the ancestry. C++ lacks reflection. The only way I can imagine is a giant loop testing the typeid's of all possible ancestors. And it hurts to imagine that.
You might want to look at Loki TypeLists if you really need to be able to track ancestry and enumerate through types. I'm not sure if what you are asking for is really possible without a bunch of work. Make sure that you aren't over-engineering here.
On a slightly different note, if you are going to use MI in this manner (i.e., the dreaded diamond), then you should be very explicit about which virtual member you want. I can't think of a good case where you want to choose the semantics of B::fn() over C::fn() without explicitly making a decision when writing D. You will probably pick one over the other (or even both) based on what the individual method does. Once you have made a decision, the requirement is that inherited changes do not change the expectations or semantic interface.
If you are really worried about swapping in a new class, say E in place of say B where E does not descend from B but offers the same interface, then you should really use the template approach though I'm not sure why there is a static_cast<> in there...
struct A {
virtual ~A() {}
virtual void f() = 0;
};
struct B: A {
virtual void f() { std::cout << "B::f()" << std::endl; }
};
struct C: A {
virtual void f() { std::cout << "C::f()" << std::endl; }
};
template <typename Base1, typename Base2>
struct D: Base1, Base2 {
void g() { Base1::f(); Base2::f(); }
};
int main() {
D<B,C> d1;
D<C,B> d2;
d1.g();
d2.g();
return 0;
}
// Outputs:
// B::f()
// C::f()
// C::f()
// B::f()
works fine and seems a little easier to look at.
Vividos has already answered the main part of the post. Even if I would use the scope operator instead of the more cumbersome static_cast<> + dereference operator.
Depending on the task at hand, maybe you can change the inheritance relationship from D to B and C for a less coupling composition (plus possibly inheritance from A). This is assuming that you don't need D to be used polimorphically as either B or C, and that you don't really require B and C sharing the same base instance.
If you opt for composition, you can receive the B and C as arguments to your constructor as references/pointers of type A, making D completely unaware of the types B and C. At that point, you can use a container to hold as many A derived objects. Your own implementation of fn() (if you so decide) or any other method.
There are already several questions that deal with this. Seems like we're running out of questions to ask. Maybe the search box should be bigger than the Ask Question button.
See
How can I avoid the Diamond of Death when using multiple inheritance?
What is the exact problem with multiple inheritance?
Is Multiple Inheritance Evil?

How can I avoid the Diamond of Death when using multiple inheritance?

http://en.wikipedia.org/wiki/Diamond_problem
I know what it means, but what steps can I take to avoid it?
A practical example:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
Notice how class D inherits from both B & C. But both B & C inherit from A. That will result in 2 copies of the class A being included in the vtable.
To solve this, we need virtual inheritance. It's class A that needs to be virtually inherited. So, this will fix the issue:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
virtual inheritance. That's what it's there for.
I'd stick to using multiple inheritance of interfaces only. While multiple inheritance of classes is attractive sometimes, it can also be confusing and painful if you rely on it regularly.
Inheritance is a strong, strong weapon. Use it only when you really need it. In the past, diamond inheritance was a sign that I was going to far with classification, saying that a user is an "employee" but they are also a "widget listener", but also a ...
In these cases, it's easy to hit multiple inheritance issues.
I solved them by using composition and pointers back to the owner:
Before:
class Employee : public WidgetListener, public LectureAttendee
{
public:
Employee(int x, int y)
WidgetListener(x), LectureAttendee(y)
{}
};
After:
class Employee
{
public:
Employee(int x, int y)
: listener(this, x), attendee(this, y)
{}
WidgetListener listener;
LectureAttendee attendee;
};
Yes, access rights are different, but if you can get away with such an approach, without duplicating code, it's better because it's less powerful. (You can save the power for when you have no alternative.)
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
In this the attributes of Class A repeated twice in Class D which makes more memory usage... So to save memory we make a virtual attribute for all inherited attributes of class A which are stored in a Vtable.
Well, the great thing about the Dreaded Diamond is that it's an error when it occurs. The best way to avoid is to figure out your inheritance structure beforehand. For instance, one project I work on has Viewers and Editors. Editors are logical subclasses of Viewers, but since all Viewers are subclasses - TextViewer, ImageViewer, etc., Editor does not derive from Viewer, thus allowing the final TextEditor, ImageEditor classes to avoid the diamond.
In cases where the diamond is not avoidable, using virtual inheritance. The biggest caveat, however, with virtual bases, is that the constructor for the virtual base must be called by the most derived class, meaning that a class that derives virtually has no control over the constructor parameters. Also, the presence of a virtual base tends to incur a performance/space penalty on casting through the chain, though I don't believe there is much of a penalty for more beyond the first.
Plus, you can always use the diamond if you are explicit about which base you want to use. Sometimes it's the only way.
I would suggest a better class design. I'm sure there are some problems that are solved best through multiple inheritance, but check to see if there is another way first.
If not, use virtual functions/interfaces.
Use inheritance by delegation. Then both classes will point to a base A, but have to implement methods that redirect to A. It has the side effect of turning protected members of A into "private" members in B,C, and D, but now you don't need virtual, and you don't have a diamond.
This is all I have in my notes about this topic. I think this would help you.
The diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a member in A that B and C, and D does not override it, then which member does D inherit: that of B, or that of C?
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C {};
D d;
d.a = 10; //error: ambiguous request for 'a'
In the above example, both B & C inherit A, and they both have a single copy of A. However D inherits both B & C, therefore D has two copies of A, one from B and another from C. If we need to access the data member an of A through the object of D, we must specify the path from which the member will be accessed: whether it is from B or C because most compilers can’t differentiate between two copies of A in D.
There are 4 ways to avoid this ambiguity:
1- Using the scope resolution operator we can manually specify the path from which a data member will be accessed, but note that, still there are two copies (two separate subjects) of A in D, so there is still a problem.
d.B::a = 10; // OK
d.C::a = 100; // OK
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
2- Using static_cast we can specify which path the compiler can take to reach to data member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
static_cast<B&>(static_cast<D&>(d)).a = 10;
static_cast<C&>(static_cast<D&>(d)).a = 100;
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using overridden, the ambiguous class can overriden the member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C { int a; };
D d;
d.a = 10; // OK: D::a = 10
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using virtual inheritance, the problem is completely solved: If the inheritance from A to B and the inheritance from A to C are both marked "virtual", C++ takes special care to create only one A subobject,
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
D d;
d.a = 10; // OK: D has only one copy of A - D::a = 10
d.A::a = 20; // OK: D::a = 20
Note that "both" B and C have to be virtual, otherwise if one of them is non-virtual, D would have a virtual A subobject and another non-virtual A subobject, and ambiguity will be still taken place even if class D itself is virtual. For example, class D is ambiguous in all of the following:
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : virtual B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : virtual B, C {};