C++ offers multiple inheritance types: public, protected, and private, each affecting how the base class members are accessible in the derived class. In this lab, we will focus on private inheritance and compare it with private composition.
§1 What is Private Inheritance? #
With private inheritance, a derived class inherits the members of a base class, but all inherited members (both public and protected) become private members of the derived class. Private inheritance is less common than public inheritance, and is typically used when the derived class needs to reuse the implementation of the base class, rather than establishing an “is-a” relationship.
Key Characteristics of Private Inheritance:
- Public members inherited from the base class become private in the derived class.
- It restricts access to inherited members from outside the derived class.
- The derived class does not satisfy the “is-a” relationship, unlike public inheritance.
Example: Let’s say we have a base class Operable that a derived class Car will use privately.
class Operable {
public:
void start() { std::cout << "Vehicle starting\n"; }
void stop() { std::cout << "Vehicle stopping\n"; }
};
class Car : private Operable {
public:
void drive() {
start(); // Car can access the parent class' start()
std::cout << "Car is driving\n";
stop(); // Car can access stop() as well
}
};
int main() {
Car myCar;
myCar.drive(); // OK: drive() is a public member of Car
// myCar.start(); // Error: start() is private in Car due to private inheritance
}
In this example:
Carinherits fromOperableusing private inheritance.- Although
Carcan callstart()andstop()internally,main()cannot accessstart()andstop()directly on aCarobject because they are private inCar.
§2 When to Use Private Inheritance? #
Private inheritance is suitable when:
- You need to reuse functionality from another class, but you do not want to expose that class’s interface as part of your derived class’s public interface.
- You don’t want an “is-a” relationship, but more of a “has-a” relationship where
Carsimply usesOperable’s methods internally without lettingCaract as aOperable.
§3 Private Composition #
Composition involves using objects of one class as data members in another class, representing a “has-a” relationship. For example, if we decided a Car “has-a” Operable, then instead of inheriting from Operable, we would include a Operable object as a member of Car.
Example: Let’s refactor the previous example using composition.
class Operable {
public:
void start() { std::cout << "Vehicle starting\n"; }
void stop() { std::cout << "Vehicle stopping\n"; }
};
class Car {
private:
Operable operable; // Car "has-a" Operable
public:
void drive() {
operable.start(); // Using Operable's functionality
std::cout << "Car is driving\n";
operable.stop();
}
};
int main() {
Car myCar;
myCar.drive(); // OK: drive() is a public member of Car
// myCar.operable.start(); // Error: operable() is private in Car
return 0;
}
In this example:
Cardoes not inherit fromOperable. Instead, it has aprivate Operablemember.CarusesOperable’s methods internally but doesn’t expose them.
§4 Private Inheritance vs. Private Composition #
Private inheritance implies that the derived class is implemented in terms of the base class rather than being an “is-a” relationship. The derived class uses the base class’s functionality internally but does not act as an instance of the base class. Composition, on the other hand, strictly represents a “has-a” relationship, where the containing class has an instance of another class as a member.
In private inheritance, the derived class can directly access all public and protected members of the base class, but these members become private within the derived class. In composition, the containing class accesses members through the member object, as it does not inherit them directly.
With private inheritance, members inherited from the base class are private in the derived class, so they cannot be accessed from outside. In composition, the member object itself is private, encapsulating the base class fully within the containing class.
Composition offers greater flexibility. Since the member object is part of the containing class, it can easily be replaced or modified without altering the containing class’ structure. Private inheritance is less flexible because it creates a tight coupling between the derived and base classes, meaning changes to either class will require more changes to other areas of the codebase.
Private inheritance is suitable when a class needs only some functionality from another class but does not want to expose the entire interface of that class. Composition is preferred for cases where the containing class needs an independent instance of another class, extending its functionality without relying on inheritance.
§5 When to Use Private Inheritance vs. Composition #
Use private inheritance when:
- You want to reuse the implementation from the base class but not expose the base class’s interface.
- You want a derived class to access base class members directly without needing to access them through an object.
Use composition when:
- You need more flexibility and a clear “has-a” relationship.
- You want to decouple classes and avoid dependencies inherent in inheritance.
- You want to change the behavior by replacing the composition object without modifying the class structure.
§6 Questions #
- When declaring an inherited class as private (
class myClass : private BaseClass), what happens to the public and protected members of the base class?
- Does private inheritance establish an “is-a” relationship between the base and derived classes? explain.
- Why might you use private inheritance instead of public inheritance? Provide an example.
- How does private inheritance differ from composition in terms of the relationship between the classes?
- In the example from the section:
What is Private Inheritance?, why canCar::drive()accessVehicle::start()andVehicle::stop()even though Car inherits from Vehicle privately?
- In terms of flexibility, why might composition be preferred over private inheritance?
- In what situation would private inheritance be more suitable than composition?