13

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?

Eduard Rostomyan
  • 7,050
  • 2
  • 37
  • 76
  • "but from my point of view, its not!" please explain; I also agree with Meyers. – Rakete1111 Jun 04 '18 at 12:16
  • So here we inherit the noncopyable part of the base class, so its more IS-A relationship, because the derived is also noncopyable. – Eduard Rostomyan Jun 04 '18 at 12:17
  • 3
    Having a non-copyable member surely will make `A` non-copyable too (unless you also add some user-defined copy and assignment). – Bo Persson Jun 04 '18 at 12:18
  • 9
    BTW, the best DASHED-WORDS description for private inheritance that I know is "IMPLEMENTED-IN-TERMS-OF". – Angew is no longer proud of SO Jun 04 '18 at 12:29
  • Private inheritance is often used with callback interfaces and message sinks. The class that is being implemented IS-A sink, but the sink interface is not public, given that it is only expected to be called from a specific other class. – Simon Richter Jun 04 '18 at 18:52

4 Answers4

16

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.

VLL
  • 9,634
  • 1
  • 29
  • 54
  • 1
    IMHO it is worth to note that the example cannot be implemented via composition using exactly `boost::noncopyable`, because it's intentionally crippled from being instantiated as a standalone object. In that sense it's indeed impossible to treat it as literal `Has-A` relationship. – luk32 Jun 05 '18 at 10:44
6

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
dbush
  • 205,898
  • 23
  • 218
  • 273
  • I like how our answers tackle the question from a different perspective (I look at it from a semantic-centered point of view while you provide an enlightenment with a technical aspect), are both correct (IMHO) but reach a different conclusion :) +1 – YSC Jun 04 '18 at 12:46
4

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.

YSC
  • 38,212
  • 9
  • 96
  • 149
  • 3
    Sorry could you clarify what you mean? `boost::noncopyable` has a semantic meaning, it is used to prevent and mark *instances* of class which derives from it as impossible to make a copy from.That is a clear semantic information. And how "grand children" are relevant here? – luk32 Jun 04 '18 at 17:12
1

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.)

sdenham
  • 525
  • 1
  • 6
  • 12