About private inheritance in C++

194 Views Asked by At

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

2

There are 2 best solutions below

6
On BEST ANSWER

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:

  • Executive::Money
  • Executive::Manager::Money

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 { ... };
0
On

I use "otherpart" to replace the Executive::get()::Money::get()
so don't need to worry about derive, if you just want to add a string

#include<iostream>

class Money
{
public:
    // void get() {std::cin >> amount;} 
    void out() {std::cout << amount <<" " << otherpart<<std::endl;};
    virtual void get() {std::cin >> amount >> otherpart;};
private:
    std::string amount;
    std::string otherpart;
};

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

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

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();}
    void out() {Manager::out();}
};

int main(void) {
    Executive compen = Executive();
    compen.get();
    compen.out();
    return 0;
}