Lab 19: Private Inheritance

Private Inheritance

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:

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:

§2 When to Use Private Inheritance? #

Private inheritance is suitable when:


§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:

§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:

Use composition when:

§6 Questions #

  1. When declaring an inherited class as private (class myClass : private BaseClass), what happens to the public and protected members of the base class?
  1. Does private inheritance establish an “is-a” relationship between the base and derived classes? explain.
  1. Why might you use private inheritance instead of public inheritance? Provide an example.
  1. How does private inheritance differ from composition in terms of the relationship between the classes?
  1. In the example from the section: What is Private Inheritance?, why can Car::drive() access Vehicle::start() and Vehicle::stop() even though Car inherits from Vehicle privately?
  1. In terms of flexibility, why might composition be preferred over private inheritance?
  1. In what situation would private inheritance be more suitable than composition?