Virtual Inheritance in C++, and solving the diamond problem – Cprogramming.com

Solving the Diamond Problem with Virtual Inheritance

By Andrei Milea

Multiple inheritance in C++ is a powerful, but tricky tool, that often leads
to problems if not used carefully. This article will teach you how to use
virtual inheritance to solve some of these common problems programmers run
into. If you’re not familiar with multiple inheritance,

The diamond problem

One of the problems that arises due to multiple inheritance is the diamond problem. A classical illustration of this is given by Bjarne Stroustrup (the creator of C++) in the following example:

class storable //this is the our base class inherited by transmitter and receiver classes
{
        public:
        storable(const char*);
        virtual void read();
        virtual void write(); 
        virtual ~storable();
        private:
        ....
}

class transmitter: public storable 
{
        public:
        void write();
        ...
} 

class receiver: public storable
{
        public:
        void read();
        ...
}

class radio: public transmitter, public receiver
{
        public:
        void read();
        ....
}

Since both transmitter and receiver classes are using the method
write() from the base class, when calling the method write() from
a radio object the call is ambiguous; the compiler can’t know which
implementation of write() to use, the one from
the transmitter class or the one from the receiver class.

To understand how this is works, let’s take a look at how the objects are
represented in memory. Inheritance simply puts the implementation of two
objects one after another, but in this case radio is both a
transmitter and a receiver, so the storable class gets
duplicated inside the radio object. The g++ compiler will complain when
compiling the code: error: ‘request for member “write” is ambiguous’, because
it can’t figure out whether to call the method write() from
storable::receiver::radio or from
storable::transmitter::radio.

Fortunately, C++
allows us to solve this problem by using virtual inheritance. In order to
prevent the compiler from giving an error we use the keyword virtual
when we inherit from the
base class storable in both derived classes:

class transmitter: public virtual storable 
{
        public:
        void read();
        ...
} 

class receiver: public virtual storable
{
        public:
        void read();
        ...
} 

When we use virtual inheritance, we are guaranteed to get only a single
instance of the common base class. In other words, the radio class will have
only a single instance of the storable class, shared by both the
transmitter and receiver classes. By having a single instance of storable, we’ve resolved the compiler’s immediate issue, the ambiguity, and the code will compile fine.

Memory Layout in Virtual Inheritance

In order to keep track of the single instance of the storable object,
the compiler will provide a virtual function table (vtable) for
classes transmitter and receiver. When a radio object is
constructed, it creates one storable instance, a transmitter
instance and a receiver instance. The transmitter and
receiver classes have a virtual pointer in their vtables that
stores the offset to the storable class. When the transmitter
class or the receiver class goes to access any fields of the
storable, it uses the virtual pointer in its vtable to find the
storable object and find the field in it. This

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, the class radio directly calls the constructor for
storable. If you need to pass any arguments to the storable
constructor, you would do so using

radio::radio ()
    : storable( 10 ) // some value that storable needs 
    , transmitter()
    , receiver()
{}

One thing to be aware of is that if either transmitter or receiver attempted to invoke the storable constructor in their initialization lists, that call will be completely skipped when constructing a radio object! Be careful, as this could cause a subtle bug!

By the way, the constructors for virtual base classes are always called before
the constructors for non-virtual base classes. This ensures that a class
inheriting from a virtual base class can be sure the virtual base class is safe to use inside the inheriting class’s constructor.

The destructor order in a class hierarchy with a virtual base class follows the same rules as the rest of C++: the destructors run in the opposite order of the constructors. In other words, the virtual base class will be the last object destroyed, because it is the first object that is fully constructed.

Delegating to a sister class

A powerful technique that arises from using virtual inheritance is to delegate
a method from a class in another class by using a common abstract base class.
This is also called cross delegation. Let’s assume we have a similar scenario
like in the diamond example, with small changes. Suppose the write()
method in transmitter class needs to access the read() method
from receiver for the radio to work (this is kind of a weird behavior,
but let’s take it for the sake of illustration) :

class storable 
{
        public:
        storable(const char*);
        virtual void read()=0; //this becomes pure virtual making storable an abstract
        virtual void write(); //class
        virtual ~storable();
        private:
        ....
}

class transmitter: public virtual storable 
{
        public:
        void write()
        {
                read();
                ....
        }
} 

class receiver: public virtual storable
{
        public:
        void read();
}

class radio: public transmitter, public receiver
{
        public:
        ...
}

int main()
{
        radio *rad = new radio();
        receiver *r1 = rad;
        transmitter *r2 =rad;

        rad->write();
        r1->write();
        r2->write();
        return 1;
}

Because of virtual inheritance, when the write() function from the transmitter class is called, the method read() from the receiver class gets called (as you may have noticed, the transmitter class doesn’t have a read() function). In the above hierarchy we can instantiate only the radio class because transmitter and receiver are abstract due to virtual inheritance.

Other considerations when using multiple inheritance in C++

When you use a class that is based on virtual inheritance like radio, you
should avoid using C style casts and use the C++ specific dynamic_cast instead
(

By Andrei MileaMultiple inheritance in C++ is a powerful, but tricky tool, that often leads to problems if not used carefully. This article will teach you how to use virtual inheritance to solve some of these common problems programmers run into. If you’re not familiar with multiple inheritance, check out
this article on multiple inheritance One of the problems that arises due to multiple inheritance is the. A classical illustration of this is given by Bjarne Stroustrup (the creator of C++) in the following example:Since bothandclasses are using the methodfrom the base class, when calling the methodfrom aobject the call is ambiguous; the compiler can’t know which implementation ofto use, the one from theclass or the one from theclass.To understand how this is works, let’s take a look at how the objects are represented in memory. Inheritance simply puts the implementation of two objects one after another, but in this caseis both aand a, so theclass gets duplicated inside the radio object. The g++ compiler will complain when compiling the code: error: ‘request for member “write” is ambiguous’, because it can’t figure out whether to call the method write() fromor fromFortunately, C++ allows us to solve this problem by using virtual inheritance. In order to prevent the compiler from giving an error we use the keywordwhen we inherit from the base class storable in both derived classes:When we use virtual inheritance, we are guaranteed to get only a single instance of the common base class. In other words, theclass will have only a single instance of theclass, shared by both theandclasses. By having a single instance of, we’ve resolved the compiler’s immediate issue, the ambiguity, and the code will compile fine.In order to keep track of the single instance of theobject, the compiler will provide a) for classesand. When aobject is constructed, it creates oneinstance, ainstance and ainstance. Theandclasses have ain their vtables that stores the offset to theclass. When theclass or theclass goes to access any fields of the, it uses the virtual pointer in its vtable to find theobject and find the field in it. This tutorial offers a comprehensive explanation of the memory layout of virtual inheritance in GCC 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, the classdirectly calls the constructor for. If you need to pass any arguments to theconstructor, you would do so using an
initialization list , as usual:One thing to be aware of is that if eitherorattempted to invoke theconstructor in their initialization lists, that call will be completely skipped when constructing aobject! Be careful, as this could cause a subtle bug!By the way, the constructors for virtual base classes are always called before the constructors for non-virtual base classes. This ensures that a class inheriting from a virtual base class can be sure the virtual base class is safe to use inside the inheriting class’s constructor.The destructor order in a class hierarchy with a virtual base class follows the same rules as the rest of C++: the destructors run in the opposite order of the constructors. In other words, the virtual base class will be the last object destroyed, because it is the first object that is fully constructed.A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class by using a common abstract base class. This is also called cross delegation. Let’s assume we have a similar scenario like in the diamond example, with small changes. Suppose themethod inclass needs to access themethod fromfor the radio to work (this is kind of a weird behavior, but let’s take it for the sake of illustration) :Because of virtual inheritance, when thefunction from theclass is called, the methodfrom theclass gets called (as you may have noticed, theclass doesn’t have afunction). In the above hierarchy we can instantiate only the radio class becauseand receiver are abstract due to virtual inheritance.When you use a class that is based on virtual inheritance like radio, you should avoid using C style casts and use the C++ specific dynamic_cast instead ( more information
on casting ). It will perform a runtime check for validity before casting, so you can be sure that the type of the object you want to cast is related (by inheritance) with the object type you want to cast into. If they are not related, the result will be a NULL pointer or a bad_cast exception in case of references.