Search code examples
c++inheritanceprivateencapsulation

Should private inheritance be used when there are no virtuals?


In C++, if I have a class Base which is a private base class of Derived but Base has no virtual functions, would it be cleaner to instead replace having inheritance with encapsulation in class Encapsulate? I imagine the only benefit to inheritance in this case would be that the base class can be accessed directly in the derived class as opposed to through memberVariable. Is one or the other practice considered better, or is it more of a personal style question?

class Base {
  public:
    void privateWork();
    // No virtual member functions here.
};

class Derived : Base {
  public:
    void doSomething() {
      privateWork();
    }
};

class Encapsulate {
    Base memberVariable;

  public:
    void doSomething() {
      memberVariable.privateWork()
    }
};

Solution

  • Remember that inheritance models "Liskov substitution": Foo is a Bar if and only if you can pass a Foo variable to every function expecting a Bar. Private inheritance does not model this. It models composition (Foo is implemented in terms of Bar).

    Now, you should pretty much always use the second version, since it is simpler and expresses the intent better: it is less confusing for people who don't know about it.

    However, sometimes, private inheritance is handy:

    class FooCollection : std::vector<Foo>
    {
    public:
        FooCollection(size_t n) : std::vector<Foo>(n) {};
    
        using std::vector<Foo>::begin;
        using std::vector<Foo>::end;
        using std::vector<Foo>::operator[];
    };
    

    This allows you to reuse some of the functionality of vector without having to forward manually the 2 versions (const + non const) of begin, end, and operator[].

    In this case, you don't have polymorphism at all: this is not inheritance, this is composition is disguise; there is no way you can use a FooCollection as a vector. In particular, you don't need a virtual destructor.