The Diamond Problem:
Because C++ allows for multiple inheritance, the diamond problem is a common issue. The "diamond problem" is inspired by the diamond shape that the inheritance hierarchy takes when the problem potentially occurs.

Let's look at an example that demonstrates this problem:
class A {
public:
virtual void read();
virtual void write();
};
class B : public A {
public:
void write();
};
class C : public A {
public:
void read();
};
class D : public B, public C {
public:
void read();
};
int main() {
D d;
d.write();
}
Both B and C are using method write, class D doesn't know which write to use. This code will not compile, it will fail because of "ambiguous access of write".
The way memory works is, the implementation of two objects are stacked one after another. The base class A is duplicated inside B, then again inside C. And both B and C are duplicated inside D. So when an instance of D tries to call write, the compiler doesn't know to call A::B::write() or A::C::write()
How to resolve this? We can rename the methods so that they are different. But if we don't want to, there are two ways.
1) Use a fully qualified function name
E.g.
d.B::write(); // code will now compile
2) Use virtual inheritance
Virtual Inheritance:
class B : public virtual A { // "public virtual" or "virtual public" are equivalent
public:
void write();
};
class C : public virtual A {
public:
void read();
};
Using the virtual keyword in the inheritance process, we ensure that class D will only have one copy of class A inside it. The code will now compile and instances of D will call the write() method from B because it's closer in the inheritance hierachy.
Constructors and Virtual Inheritance:
Because there is only a single instance of a virtual base class that is shared by multiple classes that inherit from it, the constructor for a virtual base class is not called by the class that inherits from it (which is how constructors are called, when each class has its own copy of its parent class) since that would mean the constructor would run multiple times. Instead, the constructor is called by the constructor of the concrete class. In the example above, class D directly calls the constructor for A. If you need to pass any arguments to the A constructor, you would do so using an initialization list.
One thing to be aware of is that if either class B or C invoked the A constructor in their initialization lists, that call will be completely skipped when constructing an instance of class D. Be careful when using virtual inheritance and test the constructors prudently.
Let's take a look at the order of construction and destruction in virtual inheritance:
int main() {
D d;
}
The order is: A B C D ~D ~C ~B ~A
So what did we learn? Because of virtual inheritance there is only one copy of A in the definitions so A is only called once. If we didn't have virtual in heritance, both C() and D() constructors would call A() since they are derived classes and we would have: A B A C D ~D ~C ~A ~B ~A. See C++ Constructors and Initializer Lists
E.g. With initializer lists and parameterized constructors
class A {
public:
A(int x) { cout << "Ax" << endl; }
A() { cout << "A" << endl; }
~A() { cout << "~A" << endl; }
};
class B : public virtual A {
public:
B(int x): A(x) { cout << "Bx" << endl; };
B() { cout << "B" << endl; };
~B() { cout << "~B" << endl; }
};
class C : public virtual A {
public:
C(int x): A(x) { cout << "Cx" << endl; };
C() { cout << "C" << endl; };
~C() { cout << "~C" << endl; }
};
class D : public B, public C {
public:
D(int x):B(x), C(x) { cout << "Dx" << endl; }
D() { cout << "D" << endl; }
~D() { cout << "~D" << endl; }
};
int main() {
D d;
}
What is the output?
Are you surprised it's: A Bx Cx Dx ~D ~C ~B ~A ?
This is to demonstrate the above comment about "if either class B or C invoked the A constructor in their initialization lists, that call will be completely skipped when constructing an instance of class D". We can see that this is true - both class B and C have A(x) in their initializer lists, but Ax never printed. What happened was D constructor calls B and C with parameterized values but because A is virtually inherited the initializer lists doesn't get called.
And yes, after removing the write and read methods, and removing virtual inheritance, we get the expected output:
Ax Bx Ax Cx Dx ~D ~C ~A ~B ~A
Object Size and Virtual Inheritance:
Let's start with a motivating example:
E.g.
class B {
int arr[10];
};
class B1: public B {};
class B2: public B {};
class Derived: public B1, public B2 {};
int main(void) {
cout << sizeof(Derived);
}
Assuming integers are 4 bytes, what gets printed?
80
Yes, because the Derived class inherits from both B1 and B2, two copies of the arr member are in the derived class.
What about if we used virtual inheritance? Assuming everything else stayed the same?
class B1: public virtual B {};
class B2: public virtual B {};
Now it prints 48. Saves a lot of space! 8 extra bytes are allocated for bookkeeping information stored by the compiler.