Wrox Press C++ Tutorial
The whole question of the access of inherited members in a derived class needs to be looked at more closely. Firstly, we should consider the private members of a base class in a derived class.
There was a good reason for choosing the version of the class Box with public data members, rather than the later, more secure version with private data members that we looked at. The reason was that although private data members of a base class are also members of a derived class, they remain private to the base class in the derived class, and this means that member functions added to the derived class cannot access them. They are only accessible in the derived class through function members of the base class that are not in the private section of the base class. You can demonstrate this very easily by changing all the Box class data members to private and putting a function Volume() in the derived class CandyBox, so that the class definitions become as follows:
// Version of the classes that will not compile
class Box
{
public:
Box(double lv=1.0, double bv=1.0, double hv=1.0)
{
length = lv;
breadth = bv;
height = hv;
}
private:
double length;
double breadth;
double height;
};
class CandyBox: public Box
{
public:
char* contents;
// Function to calculate the volume of a CandyBox object
double Volume() // Error - members not accessible
{ return length*breadth*height; }
CandyBox(char* str= "Candy") // Constructor
{
contents = new char[ strlen(str) + 1 ];
strcpy(contents, str);
}
~CandyBox() // Destructor
{ delete[] contents; }
};
A program using these classes will not compile. The function Volume() in the class CandyBox attempts to access the private members of the base class, which is not legal.
It is, however, legal to use the Volume() function in the base class, so if you move the definition of the function Volume() to the public section of the base class, Box, not only will the program compile but you can use the function to obtain the volume of a CandyBox object:
// Ex8_02.cpp
// Using a function inherited from a base class
#include <iostream> // For stream I/O
#include <string> // For strlen() and strcpy()
using namespace std;
class Box
{
public:
//Function to calculate the volume of a Box object
double Volume()
{ return length*breadth*height; }
Box(double lv=1.0, double bv=1.0, double hv=1.0)
{
length = lv;
breadth = bv;
height = hv;
}
private:
double length;
double breadth;
double height;
};
class CandyBox: public Box
{
// Contents the same as in Listing 8_01-02
};
int main()
{
Box myBox(4.0,3.0,2.0); // Create Box object
CandyBox myCandyBox; // Create CandyBox objects
CandyBox myMintBox("Wafer Thin Mints");
cout << endl
<< "myBox occupies "
<< sizeof myBox // Show how much memory
<< " bytes" << endl // the objects require
<< "myCandyBox occupies " << sizeof myCandyBox
<< " bytes" << endl
<< "myMintBox occupies " << sizeof myMintBox
<< " bytes";
cout << endl // Get volume of a CandyBox object
<< "myMintBox volume is " << myMintBox.Volume();
cout << endl;
return 0;
}
This example will produce the following output:

The interesting additional output is the last line. This shows the value produced by the function Volume(), which is now in the public section of the base class. Within the derived class, it operates on the members of the derived class that are inherited from the base. It is a full member of the derived class, so it can be used freely with objects of the derived class.
The value for the volume of the derived class object is 1 because, in creating the CandyBox object, the default constructor Box() was called first to create the base class part of the object, and this sets default Box dimensions to 1.
The constructor for the base part of the derived class was called automatically in the last example, but this doesn't have to be the case. We can arrange to call a particular base class constructor from the derived class constructor. This will enable us to initialize the base class data members with a constructor other than the default, or indeed to choose one or other base class constructor, depending on the data supplied to the derived class constructor.
We can demonstrate this in action using a modified version of the last example. To make the class usable, we really need to provide a constructor for the derived class which allows you to specify the dimensions of the object. We can produce an additional constructor in the derived class to do this, and call the base class constructor explicitly to set the values of the data members inherited from the base class.
// Ex8_03.cpp
// Calling a base constructor from a derived class constructor
#include <iostream> // For stream I/O
#include <string> // For strlen() and strcpy()
using namespace std;
class Box
{
public:
//Function to calculate the volume of a Box object
double Volume()
{ return length*breadth*height; }
// Base class constructor
Box(double lv=1.0, double bv=1.0, double hv=1.0)
{
cout << endl << "Box constructor called";
length = lv;
breadth = bv;
height = hv;
}
private:
double length;
double breadth;
double height;
};
class CandyBox: public Box
{
public:
char* contents;
// Constructor to set dimensions and contents
// with explicit call of Box constructor
CandyBox(double lv, double bv, double hv,
char* str= "Candy"):Box(lv, bv, hv)
{
cout << endl <<"CandyBox constructor2 called";
contents = new char[ strlen(str) + 1 ];
strcpy(contents, str);
}
// Constructor to set contents
// calls default Box constructor automatically
CandyBox(char* str= "Candy")
{
cout << endl << "CandyBox constructor1 called";
contents = new char[ strlen(str) + 1 ];
strcpy(contents, str);
}
~CandyBox() // Destructor
{ delete[] contents; }
};
int main()
{
Box myBox(4.0,3.0,2.0);
CandyBox myCandyBox;
CandyBox myMintBox(1.0,2.0,3.0,"Wafer Thin Mints");
cout << endl
<< "myBox occupies "
<< sizeof myBox // Show how much memory
<< " bytes" << endl // the objects require
<< "myCandyBox occupies " << sizeof myCandyBox
<< " bytes" << endl
<< "myMintBox occupies " << sizeof myMintBox
<< " bytes";
cout << endl
<< "myMintBox volume is " // Get volume of a
<< myMintBox.Volume(); // CandyBox object
cout << endl;
return 0;
}
As well as adding the additional constructor in the derived class, we have put an output statement in each constructor so we will know when either gets called. The explicit call of the constructor for the Box class appears after a colon in the function header of the derived class constructor. You will have perhaps noticed that the notation is exactly the same as that used for initializing members in a constructor, which we saw in the last chapter:
// Initializing members
Box(double lv=1.0, double bv=1.0, double hv=1.0):length(lv),
breadth(bv),
height(hv)
{
...
}
// Calling the base class constructor
CandyBox(double lv, double bv, double hv, char* str= "Candy"):Box(lv,bv,hv)
{
...
}
This is perfectly consistent with what we are doing here, since we are essentially initializing a Box sub-object of the derived class object. In the first case, we are explicitly calling the default constructors for the double types length, breadth and height in the initialization list. In the second instance, we are calling the constructor for Box. This causes the specific Box constructor we have chosen to be called before the CandyBox constructor is executed.
If you build and run this example, it will produce the output shown below:

The calls to the constructors are explained in the table below:
| Screen output | Object being constructed |
| Box constructor called |
|
| Box constructor called |
|
| CandyBox constructor1 called |
|
| Box constructor called |
|
| CandyBox constructor2 called |
|
The first line of output is due to the Box class constructor call, originating from the declaration of the Box object, myBox. The second line of output arises from the automatic call of the base class constructor caused by the declaration of the CandyBox object myCandyBox.
Notice how the base class constructor is always called before the derived class constructor.
The following line is due to our version of the default derived class constructor being called for the object myCandyBox. This constructor is invoked because the object is not initialized. The fourth line of output arises from the explicit identification of the Box class constructor to be called in our new constructor for CandyBox objects. The argument values specified for the dimensions of the CandyBox object are passed to the base class constructor. Next comes the output from the new derived class constructor itself, so constructors are again called for the base class first, followed by the derived class.
The last line shows that the initialization of the base part of the object myMintBox is working as it should, with the private members having been initialized by the Box class constructor.
Having the private members of a base class only accessible to function members of the base class isn't always convenient. There will be many instances where we want to have private members of a base class that can be accessed from within the derived class. As you will surely have anticipated by now, C++ provides a way to do this.
In addition to the public and private access specifiers for members of a class, you can also declare members of a class as protected. Within the class, the keyword protected has the same effect as the keyword private: members of a class that are protected can only be accessed by member functions of the class, and by friend functions of the class (also by member functions of a class that is declared as a friend of the class - we will look into friend classes later in this chapter). Using the keyword protected, we could redefine our class Box as follows:
// Listing 8_04-01
class Box
{
public:
Box(double lv=1.0, double bv=1.0, double hv=1.0)
{
cout << endl << "Box constructor called";
length = lv;
breadth = bv;
height = hv;
}
// Box destructor - just to track calls
~Box()
{ cout << "Box destructor called" << endl; }
protected:
double length;
double breadth;
double height;
};
Now the data members are still effectively private, in that they can't be accessed by ordinary global functions, but they'll still be accessible to member functions of a derived class.
We can demonstrate the use of protected data members by using this version of the class Box to derive a new version of the class CandyBox, which will access the members of the base class through its own member function, Volume().
// Ex8_04.cpp
// Using the protected access specifier
#include <iostream> // For stream I/O
#include <string> // For strlen() and strcpy()
using namespace std;
// Insert Box class definition here (Listing 8_04-01)
class CandyBox: public Box
{
public:
char* contents;
// Derived class function to calculate volume
double Volume()
{ return length*breadth*height; }
// Constructor to set dimensions and contents
// with explicit call of Box constructor
CandyBox(double lv, double bv, double hv,
char* str= "Candy"):Box(lv,bv,hv)
{
cout << endl <<"CandyBox constructor2 called";
contents = new char[ strlen(str) + 1 ];
strcpy(contents, str);
}
// Constructor to set contents
// calls default Box constructor automatically
CandyBox(char* str= "Candy") // Constructor
{
cout << endl << "CandyBox constructor1 called";
contents = new char[ strlen(str) + 1 ];
strcpy(contents, str);
}
~CandyBox() // Destructor
{
cout << "CandyBox destructor called" << endl;
delete[] contents;
}
};
int main()
{
CandyBox myCandyBox;
CandyBox myToffeeBox(2,3,4,"Stickjaw Toffee");
cout << endl
<< "myCandyBox volume is " << myCandyBox.Volume()
<< endl
<< "myToffeeBox volume is " << myToffeeBox.Volume();
cout << endl;
// cout << myToffeeBox.length; // Uncomment for an error
cout << endl;
return 0;
}
In this example, the volumes of the two CandyBox objects are calculated by invoking the function Volume(), which is a member of the derived class. This function accesses the inherited members length, breadth, and height to produce the result. The members were declared as protected in the base class and remain protected in the derived class. The program produces the output shown below:

This shows that the volume is being calculated properly for both CandyBox objects. The first object has the default dimensions produced by calling the default Box constructor, so the volume is 1, and the second object has the dimensions defined as initial values in its declaration.
The output also shows the sequence of constructor and destructor calls.
Destructors for a derived class object are called in the reverse order to the constructors for the object. This is a general rule that always applies. Constructors are invoked starting with the base class constructor and then the derived class constructor, whereas the destructor for the derived class is called first when an object is destroyed, followed by the base class destructor.
You can demonstrate that the protected members of the base class remain protected in the derived class by uncommenting the statement preceding the return statement in the function main(). If you do this, you will get the following error message from the compiler,
error C2248: 'length': cannot access protected member declared in class 'Box'
which indicates quite clearly that the member length is inaccessible.
We know that if we have no access specifier for the base class in the definition of a derived class, the default specification is private. This has the effect of causing the inherited public and protected members of the base class to become private in the derived class. The private members of the base class remain private to the base and therefore inaccessible to member functions of the derived class. In fact, they remain private to the base class regardless of how the base class is specified in the derived class definition.
We have also used public as the specifier for a base class. This leaves the members of the base class with the same access level in the derived class as they had in the base, so public members remain public and protected members remain protected.
The last possibility is to declare a base class as protected. This has the effect of making the inherited public members of the base protected in the derived class. The protected (and private) inherited members retain their original access level in the derived class.
This is summarized in the following illustration:

This may look a little complicated, but you can reduce it to the following three points about the inherited members of a derived class:
private are never accessible in a derived classpublic doesn't change the access level of its members in the derived classprotected changes its public members to protected in the derived class
Being able to change the access level of inherited members in a derived class gives you a degree of flexibility, but remember that you can only make the access level more stringent. In no way can you relax the level specified in the base class, which suggests that your base classes need to have public members if you want to be able to vary the access level in derived classes. This may seem to run contrary to the idea of encapsulating data in a class in order to protect it from unauthorized access, but, as we shall see, it will often be the case that we construct base classes in such a manner that their only purpose is to act as a base for other classes, and they aren't intended to be used for instantiating objects in their own right.