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
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.
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.
protected
inheritanceDISCLAIMER: 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 { ... };