The key property of virtual base classes is that they always produce a single unique base subobject in any object of derived class. That's exactly what's special about virtual base classes and that makes them different from regular base classes, which can produce multiple subobjects.
For example, in this hierarchy
struct B {};
struct M1 : B {};
struct M2 : B {};
struct D : M1, M2 {}
there's no virtual inheritance. All bases are inherited using regular inheritance. In this case class D
will contain two independent subobjects of type B
: one brought in by M1
, another - by M2
.
+-> D <-+
| |
M1 M2
^ ^
| |
B B <- there are two different `B`s in `D`
The task of properly destructing all subobjects when destructing D
is trivial: each class in the hierarchy is responsible of destructing its direct bases and only its direct bases. That simply means that destructor of M1
calls the destructor of its own B
subobject, destructor of M2
calls the destructor of its own B
subobject, while destructor of D
calls the destructors of its M1
and M2
subobjects.
Everything works out nicely in the above destruction schedule. All subobjects get destructed, including both subobjects of type B
.
However, once we switch to virtual inheritance things become more complicated
struct B {};
struct M1 : virtual B {};
struct M2 : virtual B {};
struct D : M1, M2 {}
Now there only one subobject of type B
in D
. Both M1
and M2
see and share the same subobject of type B
as their base.
+-> D <-+
| |
M1 M2
^ ^
| |
+-- B --+ <- there is only one `B` in `D`
If we make a naive attempt to apply the previous destruction schedule to this hierarchy, we'll end up with the B
subobject getting destructed twice: M1
calls the destructor of B
subobject, and M2
calls the destructor of the very same B
subobject.
That is, of course, completely unacceptable. Each subobject has to be destructed once and only once.
In order to solve this problem, when M1
and M2
are used as base subobjects of D
, these are explicitly prohibited to call the destructor of their B
subobject. The responsibility of calling the destructor of B
is assigned to D
's destructor. Class D
, when used as a complete independent object (i.e. serves as a most derived class), knows that there's only one B
in it and knows that the destructor of B
has to be called only once. So, the destructor of class D
will call the destructor of B
for that unique base subobject of type B
. Meanwhile, destructors of M1
and M2
will not even attempt to call the destructor of B
.
That's how it works with virtual inheritance. And that what the rule you quoted says basically. The parts that says that virtual bases' destructors are called last simply means that each class'e destructor calls destructors for its direct regular base classes, and only after that, if necessary, it calls destructors of its virtual base classes (possibly indirect). In the above example, the destructor of D
calls destructors of M1
and M2
and only after that it calls the destructor of B
.