C++ has a second means of implementing the
Let’s look at the interface topic more closely. With public inheritance, the public methods of the base class become public methods of the derived class. In short, the derived class inherits the base-class interface. This is part of the
With private inheritance, a class does inherit the implementation. For example, if you base a Student class on a string class, the Student class winds up with an inherited string class component that can be used to store a string. Furthermore, the Student methods can use the string methods internally to access the string component.
Containment adds an object to a class as a named member object, whereas private inheritance adds an object to a class as an unnamed inherited object. This book uses the term
Private inheritance, then, provides the same features as containment: Acquire the implementation, don’t acquire the interface. Therefore it, too, can be used to implement a
A New Version of the Student Class Example
To get private inheritance, use the keyword private instead of public when defining the class. (Actually, private is the default, so omitting an access qualifier also leads to private inheritance.) The Student class should inherit from two classes, so the declaration should list both:
class Student : private std::string, private std::valarray
{
public:
...
};
Having more than one base class is called
Note that the new class doesn’t need private data. That’s because the two inherited base classes already provide all the needed data members. The containment version of this example provides two explicitly named objects as members. Private inheritance, however, provides two nameless subobjects as inherited members. This is the first of the main differences in the two approaches.
Initializing Base-Class Components
Having implicitly inherited components instead of member objects affects the coding of this example because you can no longer use name and scores to describe the objects. Instead, you have to go back to the techniques you used for public inheritance. For example, consider constructors. Containment uses this constructor:
Student(const char * str, const double * pd, int n)
: name(str), scores(pd, n) {} // use object names for containment
The new version should use the member initializer list syntax for inherited classes, which uses the
Student(const char * str, const double * pd, int n)
: std::string(str), ArrayDb(pd, n) {} // use class names for inheritance
Here, as in the preceding example, ArrayDb is a typedef for std::valarray
Listing 14.4 shows the new class declaration. The only changes are the omission of explicit object names and the use of class names instead of member names in the inline constructors.
Listing 14.4. studenti.h
// studenti.h -- defining a Student class using private inheritance
#ifndef STUDENTC_H_
#define STUDENTC_H_
#include
#include
#include
class Student : private std::string, private std::valarray
{
private:
typedef std::valarray
// private method for scores output
std::ostream & arr_out(std::ostream & os) const;
public:
Student() : std::string("Null Student"), ArrayDb() {}