c++oopinheritanceprivate-inheritance

About private inheritance in C++


Why cannot I privately derive a class from both a class and another class that the class being derived from uses as a base. So, I have the the following

class Money
{
public:
    void get() {std::cin >> amount;} 
private:
    float amount;
}

class Employee
{
public:
    void get() {std::cin >> lastName;} 
private:
    std::string lastName;
}

class Manager : public Employee, private Money  //money is used to store a wage
{
public:
    void get() {Employee::get(); Money::get();} 
}

class Executive : public Manager, private Money  // money is used to store additional bonuses
//warning :direct base 'Money' inaccessible in 'Executive' due to ambiguity  
{
public:
    void get() {Manager::get(); Money::get();}
}

I expected that in the Executive class Manager::get() would invoke Money::get() to save a wage, while the other Money::get() would save the additional bonuses.

As far as I know for now, private inheritance may be applied as a form of composition or when the base's interface should be hidden from outsiders, but is useful in implementing the class being derived. I undestand that in this particular case composition is all I need, still, I cannot understand what kind of ambiguity the compiler warns me about, for private inheritance does not allow neither outside classes nor subclasses of a privately derived class to take advantage of the relation


Solution

  • When you inherit from a class in C++, it means that your class contains that base as a subclass (e.g. Money), with all of its members. When a derived class of that derived class inherits from Money again, it won't reuse that subclass, but get its own. What happens is:

    class Manager : public Employee, private Money
    // means structurally:
    Manager {
        Employee { ... }
        Money { ... }
        ...
    }
    
    // and
    class Executive : public Manager, private Money
    // means structurally
    Executive {
        Manager {
            Employee { ... }
            Money { ... }
            ...
        }
        Money { ... }
        ...
    }
    

    The problem is that Executive now has two instances of Money in its class hierarchy:

    This is the ambiguity that the compiler is warning you about.

    Solution A - Composition over inheritance

    If you really think about, it makes no sense that a Manager inherits from Money, because that would imply that a Manager is an instance of Money. It would make a lot more sense if a Manager had Money:

    class Manager {
    protected:
        Money money;
    public:
        ...
    };
    
    class Executive : public Manager { ... };
    

    Because Manager::money is a protected data member, a derived class such as Executive will be able to use it.

    Solution B - protected inheritance

    DISCLAIMER: DON'T USE INHERITANCE HERE, IT'S CLEARLY WRONG. BUT IF YOU DESPERATELY INSISTED ON IT, HERE IS THE SOLUTION:

    The most practical solution is to use protected inheritance instead. The outside world still won't have access to Money, but Executive will:

    // protected inheritance makes Money available to derived classes
    class Manager : public Employee, protected Money { ... };
    
    // don't inherit Money again, use Manager::Money
    class Executive : public Manager { ... };