Take the following hierarchy:
- base class A
- B,- Cand- Einherits from- A
- Dinherits both from- Band- C
- Finherits from- Dand- E
Talking that in code:
class A { public: int a; }
class B : public A { }
class C : public A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
or, a diagram:
       A     A   A
       |     |   |
       |     |   |
       B     C   E
        \   /   /
         \ /   /
          D   /
           \ /
            F
With this structure, every B, C and E holds their own copy of A. Following on that, D holds a copy of B and C, F holds a copy of D and E.
This causes a problem:
D d;
d.a = 10; // ERROR! B::a or C::a?
For such cases, you use virtual inheritance, creating a "diamond":
          A      A
         / \     |
        /   \    |
       B     C   E
        \   /   /
         \ /   /
          D   /
           \ /
            F
or, in code:
class A { public: int a; }
class B : public virtual A { }
class C : public virtual A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
Now you solve the previous problem, since B::a and C::a shares the same memory, but the same problem is still present, in another level:
F f;
f.a = 10; // ERROR: D::a or E::a ?
This part I am not sureConfirmed: you could use virtual inheritance from A for E to solve the problem here too. But I will leave it as it is, in order to answer another point: mixing virtual and non-virtual inheritance.
But consider that you want to E::a from a F have a different value of D::a from the same F. For that, you must type-cast your F:
F *f = new F;
(static_cast<D*>(f))->a = 10;
(static_cast<E*>(f))->a = 20;
Now your F* f holds two different values of A::a.
About memory management
Taking these classes, from above example:
class A { public: int a; }
class B : public virtual A { }
class C : public virtual A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
One could draw the following memory diagram:
For class A:
+---------+
|    A    |
+---------+
For classes B, C and E:
+---------+
|    B    |
+---------+
     |
     V
+---------+
|    A    |
+---------+
Meaning that for every instance of B, C and E you create, you create another instance of A.
For class D, things are a bit more complicated:
+---------------------------------------+
|                   D                   |
+---------------------------------------+
       |                         |
       V                         V
+--------------+         +--------------+
|      B       |         |       C      |
+--------------+         +--------------|
       |                         |
       V                         V
+---------------------------------------+
|                   A                   |
+---------------------------------------+
Meaning that when you create an D, you have one instance of B and one instance of C. But instead of creating a new instance of A for each B and C, a single instance is created for both.
And for F:
+-------------------------------------------------------+
|                           F                           |
+-------------------------------------------------------+
                    |                              |
                    V                              V
+---------------------------------------+     +---------+
|                   D                   |     |    E    |
+---------------------------------------+     +---------+
       |                         |                 |
       V                         V                 |
+--------------+         +--------------+          |   
|      B       |         |       C      |          |
+--------------+         +--------------+          |
       |                         |                 |
       V                         V                 V
+---------------------------------------+     +---------+
|                   A                   |     |    A    |
+---------------------------------------+     +---------+
Meaning that when you create a F, you have: one instance of D and one of E. Since E does not virtually inherits from A, a new instance of A is created when E is created.
Concerning virtual and pure virtual methods
Take these classes:
class A { virtual void f() = 0; }
class B : public A { virtual void f(int value) { std::cout << "bar" << value; } }
class C : public B { virtual void f() { std::cout << "foo"; f(42); } }
A is called abstract (some also call interface), since there are pure virtual functions.
B is also abstract, since it inherits from A and does not override the A::f(void) method, which is pure virtual, even defining its own methods (B::f(int))
C is an implementation of B, since it does define all functions that are required to turn B into a "full" class - which is overriding A::f(void).
This answer is not complete, but it gives a general idea.