Does private inheritance always mean "HAS-A"?

1.6k Views Asked by At

According to my favorite author , Mr Scott Meyers, the private inheritance and composition means the same thing aka Has-A relationship. Thus everything that can be gained from composition (containment, when class A has class B as its member) can be gained by private inheritance, and visa-versa.

So the following code should be a Has-A relationship, but from my point of view, its not!

class A : private boost::noncopyable {.. this is irrelevant };

Can anyone please tell me that I am missing? Or how this code can be implemented through composition?

4

There are 4 best solutions below

1
On BEST ANSWER

You example can be implemented through composition like this:

class A {
private:
    class B {
        B(const B&) = delete;
        B& operator=(const B&) = delete;
    } b;
};

A is noncopyable, because its member b is noncopyable.

1
On

boost::noncopyable has no real semantic meaning, this is just an implementation detail to disallow grand-children.

class A : private boost::noncopyable {};

A does not have a boost::noncopyable, since boost::noncopyable is empty, both literally and of meaning. Here, you would say "A is noncopyable", but I generally agree with Meyers' point of view in the general case.

1
On

Your example is still a HAS-A relationship.

Given the following class as an example which is roughly equivalent to boost:noncopyable:

class X {
private:
    X(const X &);
    X &operator=(const X &);
public:
    X() {}
};

The following two classes have the same functionality:

class A : private X {
public:
    int a;
    char b;
};

class B {
public:
    int a;
    char b;
    X x;
};

In this example, A inherits privately from X while B contains an instance of X. A cannot be copied because it can't call the parent's copy constructor, and B cannot be copied because it can't call the copy constructor of one of its members.

A a1;
A a2(a1);   // error
B b1;
B b2(b1);   // error
0
On

This question can be answered in a way that avoids the specifics of discussing a particular example. A class that inherits publicly starts off with everything that defines its parent's semantics - its public functions, and also its public state variables, if it has any. If none of these are overridden, it conforms to the Liskov substitution principle, and it is a widely-accepted design principle that overrides of these properties should be done in such a way that preserves substitutability.

With private inheritance, none of this applies, unless the programmer chooses to implement (or re-implement), in the derived class, all the public properties of the parent class, in a way that preserves substitutability. As C++ does not require a privately-derived class to implement versions of its parent's public methods and variables, this is no different (other than minor and formulaic changes in the code) than if the derived class instead contained an instance of the parent class as a private member. In particular, with private inheritance, the derived class is not, in any functional or operational way, a sub-type of the parent's type, and if your language treats derived classes as if they are subtypes, an opportunity for misunderstanding and confusion has been created (though it should be noted that unless your language has a way to enforce the semantic validity of subtypes (which C++ does not), then this is effectively a matter of style.)