Chuck designed and provided the original reference implementations for bitset and also bitstring, the precursor to vector, while an active member of the C++ standards committee in the early 1990s.
We use the term hierarchy because everyone else does, but the graph representing multiple inheritance relationships is in general a directed acyclic graph (DAG), also called a lattice, for obvious reasons.
The presence of these pointers explains why the size of b is much larger than the size of four integers. This is (part of) the cost of virtual base classes. There is also VPTR overhead due to the virtual constructor.
Note that the virtual inheritance is crucial to this example. If Top were not a virtual base class, there would be multiple Top subobjects, and the ambiguity would remain. Dominance with multiple inheritance only comes into play with virtual base classes.
Jerry Schwarz, the author of IOStreams, has remarked to both of us on separate occasions that if he had it to do over again, he would probably remove MI from the design of IOStreams and use multiple stream buffers and conversion operators instead.
The C++ standards states: "No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template… Every program shall contain exactly one definition of every non-inline function or object that is used in that program."
There is some similarity between inner classes and subroutine closures, which save the reference environment of a function call so it can be reproduced later.
This is an oversimplification. Sometimes even when it seems like an atomic operation should be safe, it may not be, so you must be very careful when deciding that you can get away without synchronization. Removing synchronization is often a sign of premature optimization – things that can cause you a lot of trouble without gaining much. Or anything.
This is in contrast to Java, where you must hold the lock in order to call notify() (Java’s version of signal()). Although Posix threads, on which the ZThread library is loosely based, do not require that you hold the lock in order to call signal() or broadcast(), it is often recommended.