【问题标题】:Does private inheritance always mean "HAS-A"?私有继承是否总是意味着“HAS-A”?
【发布时间】:2018-11-13 18:38:00
【问题描述】:

根据我最喜欢的作者Mr Scott Meyers 所说,private 继承和组合意味着相同的东西,也就是 Has-A 关系。因此,可以从组合中获得的所有内容(包含,当类 A 具有类 B 作为其成员时)都可以通过私有继承获得,反之亦然。

所以下面的代码应该是Has-A关系,但在我看来,不是!

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

谁能告诉我我失踪了?或者这段代码如何通过组合来实现?

【问题讨论】:

  • “但在我看来,它不是!”请解释;我也同意迈耶斯的观点。
  • 所以这里我们继承了基类的不可复制部分,所以它更多的是IS-A关系,因为派生的也是不可复制的。
  • 拥有一个不可复制的成员肯定会使A 也不可复制(除非您还添加了一些用户定义的副本和分配)。
  • 顺便说一句,我所知道的关于私有继承的最佳 DASHED-WORDS 描述是“IMPLEMENTED-IN-TERMS-OF”。
  • 私有继承通常与回调接口和消息接收器一起使用。正在实现的类是一个接收器,但接收器接口不是公共的,因为它只需要从特定的其他类调用。

标签: c++ inheritance implementation noncopyable


【解决方案1】:

你的例子可以通过这样的组合来实现:

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

A 是不可复制的,因为它的成员 b 是不可复制的。

【讨论】:

  • 恕我直言,值得注意的是,该示例不能通过完全使用 boost::noncopyable 的组合来实现,因为它被故意实例化为独立对象而被削弱。从这个意义上说,确实不可能将其视为文字 Has-A 关系。
【解决方案2】:

您的示例仍然是 HAS-A 关系。

以下面的类为例,大致相当于boost:noncopyable

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

以下两个类具有相同的功能:

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

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

在此示例中,A 私下继承自 X,而 B 包含 X 的实例。 A 无法复制,因为它无法调用父级的复制构造函数,B 无法复制,因为它无法调用其成员之一的复制构造函数。

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

【讨论】:

  • 我喜欢我们的答案如何从不同的角度解决问题(我从以语义为中心的角度看待它,而您提供技术方面的启发),都是正确的(恕我直言)但得出不同的结论:) +1
【解决方案3】:

boost::noncopyable 没有真正的语义含义,这只是一个禁止孙子的实现细节。

class A : private boost::noncopyable {};

A 没有 boost::noncopyable,因为boost::noncopyable 是空的,无论是字面意思还是含义。在这里,您会说“A 不可复制”,但我一般同意 Meyers 在一般情况下的观点。

【讨论】:

  • 抱歉,您能澄清一下您的意思吗? boost::noncopyable具有语义意义,用于防止和标记从它派生的类的instances不能复制。这是一个清晰的语义信息。以及“孙子”在这里的相关性如何?
【解决方案4】:

可以通过避免讨论特定示例的细节来回答这个问题。一个公开继承的类从定义其父级语义的所有内容开始——它的公共函数,以及它的公共状态变量(如果有的话)。如果这些都没有被覆盖,则它符合Liskov substitution principle,这是一个被广泛接受的设计原则,即应该以保持可替换性的方式覆盖这些属性。

对于私有继承,这些都不适用,除非程序员选择在派生类中实现(或重新实现)父类的所有公共属性,以保留可替换性。由于 C++ 不需要私有派生类来实现其父类的公共方法和变量的版本,因此这与派生类包含父类的实例并没有什么不同(除了代码中的微小和公式化更改)私人会员。特别是,对于私有继承,派生类在任何功能或操作方面都不是父类型的子类型,并且如果您的语言将派生类视为子类型,则存在误解和混淆的机会已创建(尽管应该注意,除非您的语言有办法强制子类型的语义有效性(C++ 没有),否则这实际上是一种风格问题。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 2015-09-16
    • 2021-10-01
    • 1970-01-01
    • 2010-10-02
    • 2014-08-15
    • 1970-01-01
    相关资源
    最近更新 更多