As we have discussed in the post - c++ type of inheritance, we have covered private inheritance (a.k.a ) implementation inheritance, protected inheritance and public inheritance (a.k.a type inheritance). In this topic we are going to discuss virutal inheritance.
However, called virtual inheritance, it does not have close relationship with the private/protected/public inheritance. virtual inheritance is often used in the cases where multiple inheritance hierarichy is used.
For our discussion, let's first see an class hierarchy.
hierarchy_example 1 ZooAnimal Endangered / \ / -V- -V- / / \ / Bear Racoon / \ \ / ------------\ \ / \ \ --------- / \ \ / ------ Panda
ZooAnimal is a virtual base class of Raccon and Bear.
Before we dive into the virtual inheritance, let's first examine the problem without virtual base/inheritance.
C++ is a language which supports multiple inheritance. We have learned that when a class subclass another class, the super class become a subobject of the derived class, suppose if through multiple inheritance tree, a class appears twice on both side, then it has some problem this has two implications
1. it waste spaces
2. a more serious problem is ambiguity, which member method/data object to call?
virtual inhertiance is just to address the issue we have identified earlier. under virtual inheritance: there is only a single, shared base class subobject is inherited regardless of how many times the base class occurs within the derivation hierarchy.
so the importance of virtual inheritance under multiple inhertiance is said, let see some code examples.
/*
* ZooAnimal to support a void paramter constructor
*/
class ZooAnimal {
public:
ZooAnimal(string name, bool onExhibit, string fam_name) : _name(name), _onExhibit(onExhibit), _fam_name(fam_name) {}
// We will see under what situation we need a void parameter ctor
// ZooAnimal() : _name(NULL), _onExhibit(false), _fam_name(NULL) {}
virtual ~ZooAnimal();
virtual ostream& print (ostream &) const;
string name() const { return _name; }
string family_name() const { return _fam_name; }
private:
protected:
bool _onExhibit;
string _name;
string _fam_name;
} ;
class Bear: public virtual ZooAnimal {
public:
enum DanceType { two_left_feet, macarena, fandango, waltz } ;
Bear(string name, bool onExhibit= true) : ZooAnimal(name, onExhibit, "Bear") , _dance(two_left_feet)
{}
virtual ostream & print(ostream& ) const;
void dance(DanceType );
private:
protected:
DanceType _dance;
};
class Raccoon : virtual public ZooAnimal {
public:
Raccoon(string name, bool onExhibit = true) : ZooAnimal(name, onExhibit, "Raccoon"), _pettable(false) {}
virtual ostream& print(ostream& ) const;
bool pettable() const { return _pettable; }
void pettable(bool petval) { _pettable = petval; }
private:
protected:
bool _pettable;
};
class Endangered
{
public:
enum CriticalLevel { critical, high, low, trivial };
enum EndangeredCause { environment, population } ;
Endangered(EndangeredCause cause, CriticalLevel level) : _cause(cause), _level(level) { }
private:
protected:
CriticalLevel _level;
EndangeredCause _cause;
};
class Panda : public Bear, public Raccoon, public Endangered
{
public:
Panda(string name, bool onExhibit = true) ;
virtual ostream& print(ostream &) const;
bool sleeping () const { return _sleeping; }
private:
protected:
bool _sleeping;
};
Special Initialization Semantics
Panda::Panda(string name, bool onExhibit) : ZooAnimal (name, onExhibit, "Panda"),
Bear(name, onExhibit),
Raccoon(name, onExhibit),
Endangered(Endangered::environment,
Endangered::critical),
_sleeping(false)
{
}
class Bear: public virtual ZooAnimal {
public:
Bear(string name, bool onExhibit= true) : ZooAnimal(name, onExhibit, "Bear") , _dance(two_left_feet)
{}
protected:
// when an intermediate derived class
Bear() : _dance( two_left_feet) {}
// rest are the same..
};
class ZooAnimal {
protected:
ZooAnimal() : _name(NULL), _onExhibit(false), _fam_name(NULL) {}
} ;
Panda::Panda(string name, bool onExhibit) : ZooAnimal (name, onExhibit, "Panda"),
Endangered(Endangered::environment,
Endangered::critical),
_sleeping(false)
{
}
Construcotr and destructor order
/**
* hierarchy_example 2
*
* Character ZooAnimal ToyAnimal
* ^ ^ ^
* | v v
* | | /
* RockCharacter Bear /
* ^ ^ /
* | | /
* \ / --- -
* \ / /
* TdeddyBear
*
*/
/*
* there is a basic rule in terms the order of the Constructor and Destructor Order
* Virtual base classes are always constructed prior to to nonvirutal base classes regardless where they appear in the inheritance hierarchy.
* Let's see the example above, we are going to illustrate the discussion we have seen before.
*
*/
class Character {} ;
class BookCharacter : public Character { };
class ToyAnimal { }
class TeddyBear : public BookCharacter, public Bear, public virtual ToyAnimal
{
};
TeddyBear Paggington;
ZooAnimal();
ToyAnimal();
Character()
BookCharacter()
Bear();
TeddyBear()