Another situation that calls for using private inheritance is if you want to redefine virtual functions. Again, this is a privilege accorded to a derived class but not to a containing class. With private inheritance, the redefined functions would be usable just within the class, not publicly.
Tip
In general, you should use containment to model a
Protected Inheritance
Protected inheritance is a variation on private inheritance. It uses the keyword protected when listing a base class:
class Student : protected std::string,
protected std::valarray
{...};
With protected inheritance, public and protected members of a base class become protected members of the derived class. As with private inheritance, the interface for the base class is available to the derived class but not to the outside world. The main difference between private and protected inheritance occurs when you derive another class from the derived class. With private inheritance, this third-generation class doesn’t get the internal use of the base-class interface. That’s because the public base-class methods become private in the derived class, and private members and methods can’t be directly accessed by the next level of derivation. With protected inheritance, public base-class methods become protected in the second generation and so are available internally to the next level of derivation.
Table 14.1 summarizes public, private, and protected inheritance. The term
Table 14.1. Varieties of Inheritance
Redefining Access with using
Public members of a base class become protected or private when you use protected or private derivation. Suppose you want to make a particular base-class method available publicly in the derived class. One option is to define a derived-class method that uses the base-class method. For example, suppose you want the Student class to be able to use the valarray sum() method. You can declare a sum() method in the class declaration and then define the method this way:
double Student::sum() const // public Student method
{
return std::valarray
}
Then a Student object can invoke Student::sum(), which, in turn, applies the valarray
There is an alternative to wrapping one function call in another: use a using declaration (such as those used with namespaces) to announce that a particular base-class member can be used by the derived class, even though the derivation is private. For example, suppose you want to be able to use the valarray min() and max() methods with the Student class. In this case, in studenti.h, you can add using declarations to the public section:
class Student : private std::string, private std::valarray
{
...
public:
using std::valarray
using std::valarray
...
};
The using declaration makes the valarray
cout << "high score: " << ada[i].max() << endl;
Note that the using declaration just uses the member name—no parentheses, no function signatures, no return types. For example, to make the valarray operator[]() method available to the Student class, you’d place the following using declaration in the public section of the Student class declaration:
using std::valarray
This would make both versions (const and non-const) available. You could then remove the existing prototypes and definitions for Student::operator[](). The using declaration approach works only for inheritance and not for containment.
There is an older way to redeclare base-class methods in a privately derived class: You place the method name in the public section of the derived class. Here’s how you would do that:
class Student : private std::string, private std::valarray
{
public:
std::valarray
...
};
This looks like a using declaration without the using keyword. This approach is