CS202 Programming
Systems
Lecture Notes #6
Deriving Classes
using
Multiple
and Virtual Inheritance
Lecture
and Reference
With single inheritance each derived class has one base class. In certain cases, creating such a tree-like hierarchy may be too restrictive. We may find that our designs make more sense when classes have more than one direct base class. Such hierarchies are built using multiple inheritance.
In the following sections we introduce what it means to design with more than one direct base class. First, multiple inheritance terminology is introduced and the objectives of using more than one direct base class are investigated. Once this material is understood, we will be ready to learn how to use multiple inheritance and virtual inheritance.
6.1 Hierarchies With More Than One Base Class
In situations where a new class has attributes and behavior in common with more than one class, we may choose to implement a multiple inheritance hierarchy. There are two disadvantages to creating multiple inheritance hierarchies. First, it is harder than single inheritance to implement and maintain. Second, it is more restrictive than single inheritance. We recommend its use only after considering other options. None the less, there are times when multiple inheritance is the most elegant solution when compared to the alternatives.
With multiple inheritance, a derived class can
inherit from more than one base class. Derived classes can add to the
capabilities of the base classes by providing additional data members and
member functions in the same way that they do with single inheritance. As with
single inheritance, we form a multiple inheritance hierarchy by specifying the
parents in the derived class' derivation list. We do not need to alter the base
classes to specify which classes are derived from them. Instead, we specify in
a derived class all of the direct base classes that will be its parents.
The members of these base classes are then inherited by the derived class.
Figure 6-1 illustrates the difference between single inheritance and multiple inheritance. With single inheritance, one or more classes are derived from a single base class. With multiple inheritance, one or more classes are derived from multiple base classes.
Single
Inheritance Multiple
Inheritance . . . Two or
more direct base classes One
direct base class

![]()
![]()
![]()


![]()
![]()
Figure 6-1: Single Inheritance versus Multiple Inheritance
With multiple inheritance we can implement a set of classes and then later decide that another class is actually a composite of those classes. Without multiple inheritance, we would have to include an object of another class as part of our class and then use its attributes and behavior in the implementation of our class. Multiple inheritance provides the simplicity of inheriting behavior from more than one base class and minimizes reimplementation of existing behavior.
6.2 Caution
There has been a significant amount of debate over the usefulness and viability of creating multiple inheritance hierarchies. Before getting into the details of multiple inheritance, we should step back and understand its objectives and drawbacks.
It is important to realize that multiple inheritance is not needed for all object-oriented design solutions. In fact, multiple inheritance is not required to perform true object-oriented programming. This is because multiple inheritance diverges away from a pure hierarchy and allows us to form a more complex set of relationships. Use multiple inheritance when it makes sense, but be cautious to limit its use to only those cases where it is needed.
6.3 Creating a Multiple Inheritance Hierarchy
Now that we understand what multiple inheritance allows us to do, it is time to learn how to implement classes using it. We will find that much of what we learned about single inheritance in Lecture 11 applies directly to multiple inheritance. The primary difference is that we are now dealing with more than one base for any derived class and must learn how to deal with the complexities that result.
The following sections begin by describing a multiple inheritance hierarchy. Next we describe the syntax for creating multiple inheritance hierarchies. Finally, we investigate the order in which constructors are invoked and demonstrate its use with an example.
6.3.1 Multiple Inheritance
Multiple Inheritance: A class hierarchy where a derived class has more than one direct base class.
Designs that result in a class having more than one base class form a multiple inheritance hierarchy. A class with multiple publicly derived base classes has all of the attributes and behavior of its base classes.
Figure 6-2 illustrates a multiple inheritance hierarchy. The direct base classes are savings and equity. The savings class represents an account where deposits earn interest. The equity class represents a class for managing investments. The assets class represents a class that manages investments and earns interest on any cash left on deposit.

Figure 6-2: An assets Class Using Multiple Inheritance
The assets class must specify in its definition that it is derived from both savings and equity. This means that both savings and equity are the parents of assets. The assets class inherits the attributes and behavior of both savings and equity.
6.3.2 The Syntax of Multiple Inheritance
To specify a derived class when there is more than one base class, we add each direct base class name as part of the derived class' header. This is the same as with single inheritance, except there is a comma separated list of base classes.
The following example illustrates the syntax for creating a multiple inheritance hierarchy using public derivation:
class assets : public savings, public equity {
public:
...
};
The derivation list (i.e., class assets : public savings, public equity) establishes a hierarchy and specifies that the assets class is formed from two base classes (savings and equity) using public derivation.
There are two restrictions that we should keep in mind when designing a multiple inheritance hierarchy. The definition cannot be cyclical, meaning that a derived class cannot ultimately be its own parent. In addition, a direct base class cannot be specified more than once for any given derived class.
6.3.3 Defing a Multiple Inheritance Hierarchy
The following are the class definitions for the class hierarchy illustrated in Figure 6-2. This uses both single inheritance and multiple inheritance including direct and indirect base classes.
//account.h
class account {
public:
account(const char* ="none", float=0);
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class savings : public account {
public:
savings(const char* ="none", float=0);
float get_interest();
private:
float interest;
};
//equity.h
class equity {
public:
equity(const char* ="none", float=0);
float get_holdings();
private:
char name[32];
float holdings;
};
//assets.h
#include "account.h"
#include "equity.h"
class assets : public savings, public equity {
public:
assets(const char* ="none", float=0, float=0);
float get_total();
private:
float total;
};
The following diagram shows the relationship of each of the account, savings, equity, and assets components of an assets object.

Figure 6-3: Composition of an assets Object
6.3.4 Order of Constructor Invokation
As we learned with single inheritance, the constructor for a base class is always implicitly invoked before a derived class. This means that a derived class' constructor can assume that the base class' members have already been initialized once it executes. This applies to multiple inheritance, with the addition that all base class constructors are always implicitly invoked prior to the derived class' constructor.
The order in which the constructors are invoked is based on the order of the base class declarations in the derived class. class assets : public savings, public equity means that the savings constructor is invoked first followed by the equity constructor. Thus, the order of constructor invokation for these classes is savings, equity, and assets.
As long as each base class has a default constructor, the derived class will automatically invoke them. If not, an explicit call to a base class constructor taking arguments must be made in the initialization list of the derived class.
6.3.5 Direct Base Class Constructors with Arguments
If one of the base class constructors expects an argument list, the derived class constructor must supply the actual arguments expected by the base class constructor in its initialization list. For example, if the savings and equity constructors expect arguments, the assets class constructor must provide them as follows:
class assets : public savings, public equity {
public:
assets(const char* n, float s) :
savings(n, s),
equity(n, e) {
}
...
};
The derived class constructor must supply the actual arguments expected by each base class constructor in its initialization list. The order these are listed in the initialization list is not important and does not alter the order of constructor invokation. The order in which base class constructors are invoked is the order in which the base classes are specified in the derivation list.
6.3.4 An Example of a Multiple Inheritance Hierarchy
The following is an example using multiple inheritance. It implements the hierarchy illustrated in Figure 6-2. All constructors take arguments, therefore all derived classes explicitly invoke their base class constructors passing the appropriate arguments. The main program invokes all of the operations inherited through an object of the assets class.
//account.h (Ex1801)
class account {
public:
account(const char* ="none", float=0);
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class savings : public account {
public:
savings(const char* ="none", float=0);
float get_interest();
private:
float interest;
};
//account.cpp (Ex1801)
#include <iostream>
#include <cstring>
using namespace std;
#include "account.h"
account::account(const char* n, float b) :
balance(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
const char* account::get_name() {
return (name);
}
float account::get_balance() {
return balance;
}
savings::savings(const char* n, float b) :
account(n, b),
interest(0) {
}
float savings::get_interest() {
return interest;
}
//equity.h (Ex1801)
class equity {
public:
equity(const char* ="none", float=0);
float get_holdings();
private:
char name[32];
float holdings;
};
//equity.cpp (Ex1801)
#include <iostream>
#include <cstring>
using namespace std;
#include "equity.h"
equity::equity(const char* n, float b) :
holdings(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
float equity::get_holdings() {
return holdings;
}
//assets.h (Ex1801)
#include "account.h"
#include "equity.h"
class assets : public savings, public equity {
public:
assets(const char* ="none", float=0, float=0);
float get_total();
private:
float total;
};
//assets.cpp (Ex1801)
#include <iostream>
using namespace std;
#include "assets.h"
assets::assets(const char* n, float s, float e) :
savings(n, s),
equity(n, e),
total(s+e) {
}
float assets::get_total() {
return (total);
}
//main.cpp (Ex1801)
#include <iostream>
using namespace std;
#include "assets.h"
int main() {
assets a("Pete Peterson", 500, 3000);
//inherited from account/savings
cout <<"name = " <<a.get_name() <<endl;
cout <<"balance = " <<a.get_balance() <<endl;
cout <<"interest = " <<a.get_interest() <<endl;
//inherited from equity
cout <<"holdings = " <<a.get_holdings() <<endl;
//assets member function
cout <<"total = " <<a.get_total();
return (0);
}
This results in the following output:
name = Pete Peterson
balance = 500
interest = 0
holdings = 3000
total = 3500
6.4 Member Ambiguities and Member Hiding
In Lecture 11 we learned how hiding applied to single inheritance. We found that by hiding base class members we can redefine the base class member functions without changing the base class' client interface. This allows client applications to continue to function while providing the ability to create and modify derived classes. Now, let's apply this concept to multiple inheritance and see how it can be used when there is more than one base class.
The following sections discuss how ambiguities can occur between base classes within a multiple inheritance hierarchy. We then examine how to resolve them first by explicitly accessing the desired member and then by hiding the ambiguity in the derived class.
6.4.1 Resolving Ambiguities
When members of two different base classes have the same name, an ambiguity results when that member is used. For example, get_name is a member function of the savings class. If get_name was also a member function of the equity class, an attempt to access get_name from either the assets class or a client of the assets class would result in an ambiguous access. This ambiguity cannot be resolved by the compiler, but must be resolved at the time the access is made either by the class or by the client.
The ambiguity can be resolved by using the base class name and the scope resolution operator when accessing the ambiguous member (e.g., savings::get_name). This is the only way such an ambiguity can be resolved within the derived class when accessing the base class member. The next section discusses a better approach for eliminating ambiguities for clients of the derived classes.
6.4.2 Hiding Ambiguities
Members in a base class are hidden anytime we specify a data member or a member function in a derived class that has the same name as a member in one of the base classes. When that member is accessed, either from a client of the derived class or within the derived class itself, it is the derived class member that is used.
An ambiguity resulting from the same named member in two or more bases classes can be eliminated by providing the same named member in the derived class and using it to hide the ambiguous base class members. Then, the derived class member function can explicitly provide access to the desired base class member. A client can now access the members directly without an ambiguity. The resolution of the ambiguity has been provided by the derived class.
Practical Rule: To avoid problems with ambiguous resolutions, we should examine the public members of all base classes when designing our derived class. If there are members with the same name, then we should make a rule to hide those members with a member of the same name in our derived class. This is a simple rule to follow and will avoid problems of ambiguity for clients of our classes.
6.4.3 Example
In the following example we have added two new member functions. The get_name member function was added to the equity class. It was already in the account class and was inherited by the savings class. When either the derived class or the client application uses get_name, an ambiguity results unless it is qualified by the class name and scope resolution operator.
The second new member function (statement) was added to each of the classes. Because statement is implemented in the assets class, it hides the statement functions inherited from the savings and equity classes and can therefore be used without qualification by the client program.
The following code demonstrates how to access
ambiguous base class members using the scope resolution operator and how a
derived class can hide ambiguous base class members:
//account.h (Ex1802)
class account {
public:
account(const char* ="none", float=0);
void statement();
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class savings : public account {
public:
savings(const char* ="none", float=0);
void statement();
float get_interest();
private:
float interest;
};
//account.cpp (Ex1802)
#include <iostream>
#include <cstring>
using namespace std;
#include "account.h"
account::account(const char* n, float b) :
balance(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
void account::statement() {
cout <<"Account Statement" <<endl;
cout <<" name = " <<name <<endl;
cout <<" balance = " <<balance <<endl;
}
const char* account::get_name() {
return (name);
}
float account::get_balance() {
return balance;
}
savings::savings(const char* n, float b) :
account(n, b),
interest(0) {
}
void savings::statement() {
cout <<"Savings ";
account::statement();
cout <<" interest = " <<interest <<endl;
}
float savings::get_interest() {
return interest;
}
//equity.h (Ex1802)
class equity {
public:
equity(const char* ="none", float=0);
void statement();
const char* get_name();
float get_holdings();
private:
char name[32];
float holdings;
};
//equity.cpp (Ex1802)
#include <iostream>
#include <cstring>
using namespace std;
#include "equity.h"
equity::equity(const char* n, float b) :
holdings(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
void equity::statement() {
cout <<"Equity Statement" <<endl;
cout <<" name = " <<name <<endl;
cout <<" holdings = " <<holdings <<endl;
}
const char* equity::get_name() {
return (name);
}
float equity::get_holdings() {
return holdings;
}
//assets.h (Ex1802)
#include "account.h"
#include "equity.h"
class assets : public savings, public equity {
public:
assets(const char* ="none", float=0, float=0);
void statement();
float get_total();
private:
float total;
};
//assets.cpp (Ex1802)
#include <iostream>
using namespace std;
#include "assets.h"
assets::assets(const char* n, float s, float e) :
savings(n, s),
equity(n, e),
total(s+e) {
}
void assets::statement() {
cout <<"Assets Statement" <<endl;
cout <<" name = " <<savings::get_name() <<endl;
cout <<" total assets = " <<total <<endl;
}
float assets::get_total() {
return (total);
}
//main.cpp (Ex1802)
#include <iostream>
using namespace std;
#include "assets.h"
int main() {
assets a("Pete Peterson", 500, 3000);
cout <<a.savings::get_name(); //qualify which get_name
cout <<endl;
cout <<a.equity::get_name(); //qualify which get_name
cout <<endl;
a.statement(); //ambiguity hidden by asset::statement
return (0);
}
This results in the following output:
Pete Peterson
Pete Peterson
Assets Statement
name = Pete Peterson
total assets = 3500
Multiple inheritance allows a derived class to be formed from more than one base class. Make sure when designing classes using multiple inheritance that there are no circular relationships. No class may inherit itself, even through a chain of inheritance relationships. Ambiguous member functions and data members are allowed, but will cause errors if they are used by either the client or the derived class member functions without qualifying them with the class name and the scope resolution operator.
6.5 Common Base Classes
With multiple inheritance, we should consider the
case where more than one base class within the hierarchy shares a common direct
or indirect base class. Figure 6-4
illustrates what it means to share a common base class. This is sometimes
called the deadly diamond!

Figure 6-4: Sharing a Common Base Class with Multiple Inheritance
Figure 6-4 shows both checking and savings as direct base classes of ibc and sharing a common base class account. The class ibc is an interest bearing checking account that acts like both a checking and savings account. The following are the class definitions for this class hierarchy. This illustrates multiple inheritance where the direct base classes (checking and savings) of a derived class (ibc) have a base class in common (account).
class account {
public:
account(const char* ="none", float=0);
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class checking : public account {
public:
checking(const char* ="none", float=0, float=5);
float get_charges();
private:
float charges;
};
class savings : public account {
public:
savings(const char* ="none", float=0);
float get_interest();
private:
float interest;
};
class ibc : public checking, public savings {
public:
ibc(const char* ="none", float=0, float=1000);
float get_minimum();
private:
float minimum;
};
Every object of class checking is comprised of both checking and account members and every object of class savings is comprised of both savings and account members. Since an object of class ibc inherits from both checking and savings, there are two implicit objects of class account contained in an ibc object. Figure 6-5 shows what an object of type ibc looks like.

Figure 6-5: Duplicate Base Classes With Multiple Inheritance
Notice that there are two copies of the account data members. In some situations this may be desirable, but in others such a design results in unnecessary duplication of memory. If the state of each shared base class can be different, then duplicate copies of each common base class is justified. However, if the state of each shared base class is the same, then such duplication will waste memory and raise questions as to which state is the correct one to use. When this is the case, we should create a virtual inheritance hierarchy (Section 6.6).
6.5.1 Ambiguous Access
Ambiguities arise when a base class resides more than once within the hierarchy because its members are inherited by each branch of the hierarchy. In such cases, the only way members of the duplicated base class can be accessed by their descendants is by qualifying them with the name of their derived class and the scope resolution operator.
In our ibc class, we have inherited both get_name and get_balance from the account class twice, once via checking and once via savings. Since both checking and savings inherit from account, there are two copies of account with two balance members and two name members. This means that there are two state spaces for the common account class. This is wasteful for the name since it is the same for both accounts. However, it is useful for the balance since checking and savings each have their own balances. Because there are two state spaces for account, it is ambiguous which path to take when invoking get_name and get_balance. If we access get_balance via the checking class, we will get the balance associated with the checking class. If we access get_balance via the savings class, we will get the balance associated with the savings class.
This ambiguity must be resolved by either the derived class or the client of the derived class. We can eliminate the ambiguity by explicitly qualifying the inherited member function with the name of the class and the scope resolution operator. For example, to access the get_balance member function via the checking class we write checking::get_balance.
The next section is a complete example showing the ambiguities that result from the deadly diamond!
6.5.2 An Example of Ambiguous Access
In this section, the example creates an object of type ibc that inherits from both checking and savings. Since both checking and savings inherit from account, the main program must resolve the ambiguities when accessing get_name and get_balance.
//account.h (Ex1804)
class account {
public:
account(const char* ="none", float=0);
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class checking : public account {
public:
checking(const char* ="none", float=0, float=5);
float get_charges();
private:
float charges;
};
class savings : public account {
public:
savings(const char* ="none", float=0);
float get_interest();
private:
float interest;
};
class ibc : public checking, public savings {
public:
ibc(const char* ="none", float=0, float=1000);
float get_minimum();
private:
float minimum;
};
//account.cpp (Ex1804)
#include <iostream>
#include <cstring>
using namespace std;
#include "account.h"
account::account(const char* n, float b) :
balance(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
const char* account::get_name() {
return (name);
}
float account::get_balance() {
return (balance);
}
checking::checking(const char* n, float b, float c) :
account(n, b),
charges(c) {
}
float checking::get_charges() {
return (charges);
}
savings::savings(const char* n, float b) :
account(n, b),
interest(0) {
}
float savings::get_interest() {
return (interest);
}
ibc::ibc(const char* n, float b, float m) :
checking(n, m),
savings(n, b-m),
minimum(m) {
}
float ibc::get_minimum() {
return (minimum);
}
//main.cpp (Ex1804)
#include <iostream>
using namespace std;
#include "account.h"
int main() {
ibc i("Harry Hines", 3000);
cout <<"IBC Account Statement" <<endl;
cout <<" checking name = "
<<i.checking::get_name() <<endl;
cout <<" checking balance = "
<<i.checking::get_balance() <<endl;
cout <<" savings name = "
<<i.savings::get_name() <<endl;
cout <<" savings balance = "
<<i.savings::get_balance();
return (0);
}
This results in the following output:
IBC Account Statement
checking name = Harry Hines
checking balance = 1000
savings name = Harry Hines
savings balance =
2000
6.6 Virtual Inheritance
Now that we understand the features, benefits, and drawbacks of multiple inheritance, it is now time to resolve the problems of common classes through virtual inheritance. Virtual inheritance is an extension of multiple inheritance. Its objective is to allow efficient use of memory and elimination of duplicate state spaces when designing inheritance hierarchies that share a common base class. Virtual inheritance has no use within a single inheritance hierarchy. The only time one might use virtual inheritance within a single inheritance hierarchy is when we can foresee future extensions that may result in a derived class sharing a common base class.
The following sections begin by introducing the syntax for creating virtual inheritance hierarchies. Then, we investigate the order in which constructors are invoked and discuss how constructors are used within such a hierarchy. We conclude by demonstrating the use of virtual inheritance with an example.
Before we begin, a word of caution. Be careful with the use of the term "virtual". This term has two very different meanings in C++. In Lecture #13 we will use the term to accomplish dynamic binding and pure polymorphism (as in virtual functions); this is not the same as virtual inheritance. The other is in reducing the amount of memory when dealing with common base classes (as in virtual inheritance). The following sections focus on virtual inheritance.
6.6.1 When To Use Virtual Inheritance
Virtual inheritance goes one step farther when creating inheritance hierarchies. It allows the direct base classes of a derived class to be derived from a common direct or indirect base class without duplicating data members of the common base class. Figure 6-6 illustrates what it means to eliminate duplication of data members of a common base class.

Figure 6-6: Sharing a Common Base Class with Virtual Inheritance
Figure 6-6 shows both checking and savings as direct base classes of ibc and sharing a common direct base class account. Because virtual inheritance is used to form this hierarchy, every ibc is comprised of both checking and savings attributes and operations, but only one set of account data members. Even though every object of class checking is comprised of both checking and account members and every object of class savings is comprised of both savings and account members, objects of class ibc will have only one instance of the account data members. So, an object of class ibc has memory allocated for all of the data members of class ibc, checking, savings, and just one account.
When designing class hierarchies, if there is a chance that our classes or hierarchies may, at some future point, share common base classes with other hierarchies, then we should consider designing using virtual inheritance. Such forward thinking will enable us to make efficient use of memory and will reduce unnecessary ambiguities.
6.6.2 The Syntax of Virtual Inheritance
Virtual Base Class: Common base class instantiated only once for any given multiple inheritance hierarchy.
In cases where we want only one instance of a common base class (i.e., avoiding duplication of memory), we should specify in the definition of those classes derived from the common base class that the base class is a virtual base class. By doing so, we can eliminate unnecessary duplication of memory. By making the common base class virtual, the classes derived from it contain a pointer to one base class and not the contents of the base class.
A virtual base class is specified in our class derivation lists. We add the keyword virtual before each common base class name as part of the base class header. This is the same as we use with multiple inheritance, except for the use of the keyword virtual.
The following example illustrates the syntax for creating a virtual inheritance hierarchy, using public derivation:
class common_base {...};
class base_1 : virtual public common_base {...};
class base_2 : virtual public common_base {...};
class derived : public base_1, public base_2 {...};
Notice that each path leading from the derived class to the common base class must specify that the common base class is a virtual base class. If the common base class is not a direct base class of the derived class, then the derived class does not need to use the keyword virtual in the derivation list.
Saying class base_1:virtual public common_base specifies that only one instance of the common base class will be formed, regardless of the number of paths that specify this base class as virtual. However, if a path exists in the multiple inheritance hierarchy that derives the common base class as not virtual (i.e., leaving out the keyword virtual), then this turns off virtual inheritance for that path and more than one instance of the common_base will be formed.
For example, if there are three paths from the derived class to the common base class and two of them specify the base class as virtual and the third specifies the base class as non virtual, there will be two instances of the common base class formed: one through the virtual mechanism and the other through the third path:
class common_base {...};
class path_1 : virtual public common_base {...};
class path_2 : virtual public common_base {...};
class path_3 : public common_base {...};
class derived : public path_1, public path_2, public path_3
{..};
When do we derive as virtual? If we are interested in extending the client interface for one of the direct base classes, and if there is a chance that some future path also inherits from this base class, then it should be derived as virtual. If we expect no future derivation and no common base classes exist, then leave out the keyword virtual.
6.6.3 Order of Constructor Invokation
Virtual base classes are constructed before any of their derived classes. They are also constructed before any non virtual base classes. And, destructors are still invoked in the reverse order of constructors.
When virtual inheritance is used, the most derived class in a hierarchy containing a virtual base invokes the virtual base class constructor. Any direct or indirect base classes that have initialization lists that invoke the virtual base class constructor are ignored. Constructors for virtual base classes are automatically invoked before any of their derived class constructors are invoked.
For example, as soon as we defined an object of class derived, the constructor for common_base is implicitly invoked. It is only after this is completed that the constructors for base_1 and base_2 are invoked. Any invokation of the common base class constructor in the initialization lists of base_1 and base_2 is ignored. The responsibility for the common base class initialization always resides with the most derived class. All initializations occurring in any class between the common base class and the class from which an object is being instantiated are ignored.
Just think about this for a moment and it should make sense. Since there is only one set of memory for the members of a virtual base class, it would not make sense to allow one of its children to set initial values but not the others. If two or more classes were able to initialize their virtual base class' data members to different values through use of constructors, which values would be correct? When would initialization take place? And, in what order? To avoid such confusion, virtual base classes are formed prior to any other object in the hierarchy and the most derived class is given the responsibility for initializing whether the default constructor is use or whether an explicit call to the constructor is made.
As a side note, clients of virtual base classes can
create objects of those classes, just as if they were a regular classes.
Clients can access public members and derived classes can access public and
protected members.
6.6.4 Base Classes With Default Constructors
We recommend supplying default constructors with all virtual base classes. This will avoid problems when initializing virtual base class members. If a virtual base class has arguments, then we must expect the most derived class to have full knowledge of the indirect base class constructor. Such knowledge is not recommended within complex hierarchies.
Practical Rule: A virtual base class constructor should have no formal arguments or have all default arguments.
6.6.5 Base Class Constructors with Arguments
Arguments specified for virtual base class constructors must come from the derived class that is actually creating an object. Virtual base class constructor invokations from intermediate base classes are ignored.
In the following example, we have declared checking and savings to inherit account virtually. This has resulted in only one copy of the name and balance data members. This is useful in that we do not need two copies of the name for our ibc account. Since we now only have one copy of account, we can access the get_name and get_balance member functions without risking ambiguities.
//account.h (Ex1805)
class account {
public:
account(const char* ="none", float=0);
const char* get_name();
float get_balance();
private:
char name[32];
float balance;
};
class checking : virtual public account {
public:
checking(const char* ="none", float=0, float=5);
float get_charges();
private:
float charges;
};
class savings : virtual public account {
public:
savings(const char* ="none", float=0);
float get_interest();
private:
float interest;
};
class ibc : public checking, public savings {
public:
ibc(const char* ="none", float=0, float=1000);
float get_minimum();
private:
float minimum;
};
//account.cpp (Ex1805)
#include <iostream>
#include <cstring>
using namespace std;
#include "account.h"
account::account(const char* n, float b) :
balance(b) {
strncpy(name, n, 32);
name[31] = '\0';
}
const char* account::get_name() {
return (name);
}
float account::get_balance() {
return (balance);
}
checking::checking(const char* n, float b, float c) :
account(n, b),
charges(c) {
}
float checking::get_charges() {
return (charges);
}
savings::savings(const char* n, float b) :
account(n, b),
interest(0) {
}
float savings::get_interest() {
return (interest);
}
ibc::ibc(const char* n, float b, float m) :
account(n, b), //must call from the most derived class
checking(n, m), //no effect on account, only checking
savings(n, b-m), //no effect on account, only savings
minimum(m) {
}
float ibc::get_minimum() {
return (minimum);
}
//main.cpp (Ex1805)
#include <iostream>
using namespace std;
#include "account.h"
int main() {
ibc i("Harry Hines", 3000);
cout <<"IBC Account Statement" <<endl;
cout <<" name = " <<i.get_name() <<endl;
cout <<" balance = " <<i.get_balance();
return (0);
}
This results in the following output:
IBC Account Statement
name = Harry Hines
balance = 3000
This should illustrate the point that since the constructor for a virtual base class is only invoked once, there is only one set of memory allocated for its data members. It is only by specifying an initialization list from ibc, that we can provide initial values to the virtual base class:
6.7 Public, Protected, and Private Derivation
So far, we have seen inheritance hierarchies created using public derivation. There are two other forms of derivation that are possible: protected derivation and private derivation. Each is specified in the same way as public derivation, but using either the protected or private keywords.
When do we select one type of derivation over another? If we are interested in extending the client interface for one of the direct base classes, then it should be derived as public. If we are interested in replacing the client interface but allowing future derivation, then it should be derived as protected. If we want no future derivation, then it should be derived as private.
If we were interested in extending the client interface of base_1 but replacing the client interface of base_2, our derived class' declaration would resemble the following:
class derived: public base_1, private base_2 {...};
The following sections introduce each form of derivation and address when to choose one method over another.
6.7.1 Public Derivation
Public Derivation: A base class' public members are
visible to clients of a derived class and both public and protected members are
visible to descendants.
Public derivation is useful when we are interested in extending the functionality of a base class. This is because clients as well as derived classes have access to the base class' public members. Therefore, what is public in the base class continues to act as if it is public in the derived class.
With public derivation, a base class' public members remain public within the derived class and are visible to both subsequent derived classes (descendants) and clients of the derived class. A base class' protected members remain protected within the derived class and are visible to only subsequent derived classes; they are not visible to clients. A base class' private members remain private and are not visible by either the derived class, its children, or any client.
6.7.2 Protected Derivation
Protected Derivation: A base class' public members are no longer
visible to a derived class' clients but both public and protected members are
visible to descendants.
Protected derivation is useful when we are interested in replacing the functionality of a base class and we are interested in allowing future derivation. Clients of the derived classes no longer have access to the base class' public members. They are now considered to be protected beyond the derived class. Therefore, what is public in the base class acts as if it is protected in the derived class.
With protected derivation, a base class' public members become protected within the derived class and are visible to subsequent derived classes (descendants) but are not visible to clients of the derived class. X base class' protected members remain protected within the derived class continuing to allow for subsequent derivations. A base class' private members remain private and are not visible by either the derived class, its children, or any client. Therefore, deriving subsequent classes from such a hierarchy remains a viable design strategy.
Placing a using declaration in the public section of the derived class can make a protected base class member (or a public base class member made protected through protected derivation) public in the derived class. This is a way for a derived class to selectively make part of the base class interface available to derived class client applications while keeping the remainder of the base class protected.
6.7.3 Private Derivation
Private Derivation: A base class' public members are no
longer visible to a derived class' clients and neither public or protected
members are visible to descendants, beyond the immediate derived class.
Private derivation is useful when we are interested in replacing the functionality of a base class and restricting future derivation. This is because clients of the derived classes no longer have access to the base class' public members. They are now considered to be private beyond the derived class. Therefore, what is public in the base class acts as if it is private in the derived class.
With private derivation, a base class' public members become private within the derived class and are no longer visible to either subsequent derived classes (descendants) or clients of the derived class. A base class' protected members become private within the derived class and are no longer visible to any subsequent derived classes or clients. A base class' private members remain private and are not visible by either the derived class, its children, or any client. Therefore, deriving subsequent classes from such a hierarchy becomes meaningless. It is the best way we have to restrict future derivation.
Placing a using declaration in the public section of the derived class can make a public or protected base class member (made private through private derivation) public in the derived class. Placing a using declaration in the protected section of the derived class can make a public or protected base class member (made private through private derivation) protected in the derived class.
Private derivation implements an "implemented in terms of" relationship. The same effect can often be accomplished by using an embedded object of the base class implementing a "has a" relationship.
6.7.4 Summary of Derivation
Remember when we create an inheritance hierarchy it is from our derived classes that we specify the base class(es) and the form of derivation to take place. The derivation from a base class to a derived class may be either public, protected, or private. If public derivation is selected, the public members of the base class are also considered to be public members of the derived class. A base class' members remain public, private, or protected as originally declared. However, if protected derivation is selected, the public members of the base class become protected members of the derived class. A base class' public members are considered protected now, but the base class' private and protected members remain as originally declared. If private derivation is selected, the public and protected members of the base class become private members of the derived class. This means that these members can be accessed by the derived class' member functions and friend functions, but they are not accessible to the clients of the derived class. A base class' public and protected members are considered private now, but the base class' private members remain as originally declared. These characteristics are summarized in Table 16-1.

Table 16-1: The Visibility of Base Class Members within a Derived Class
Public derivation means that public members of the base class are public members of the derived class and protected members of the base class are protected members of the derived class. Therefore, public base class members are available to clients of the derived class and protected base class members are available to member functions, friends of the derived class, and subsequent derived classes, but not clients.
Protected derivation means that public members of the base class are protected members of the derived class and protected members of the base class are protected members of the derived class. Therefore, public and protected base class members are available to member functions, friends of the derived class, and subsequent derived classes, but not clients of the derived class.
Private derivation means that public members of the base class are private members of the derived class and protected members of the base class are private members of the derived class. Therefore, public and protected base class members are available to member functions and friends of the derived class, but not clients or subsequent derived classes.
With virtual inheritance, the type of derivation (public, protected, or private) follows the same guidelines outlined for multiple inheritance. We may use public, protected, or private derivation for each of the base classes. Each base class need not have the same form of derivation. Some may be derived as public while others may be derived as protected or private. This applies to virtual as well as non virtual base classes.
Remember that regardless of the type of derivation, private members are always private to the class and are never available to any derived classes except for friends of the class. Whenever a class inherits information from a class which is also a derived class, the new derived class does not have more access to the original base class than its parent.