私有继承总是意味着 "HAS-A" 吗?
Does private inheritance always mean "HAS-A"?
根据我最喜欢的作者 Mr Scott Meyers 的说法,私有 继承和组合意味着相同的事情,即 Has-A 关系。因此,可以从组合中获得的一切(包含,当 class A 具有 class B 作为其成员时)都可以通过私有继承获得,反之亦然。
所以下面的代码应该是一个Has-A关系,但在我看来,它不是!
class A : private boost::noncopyable {.. this is irrelevant };
谁能告诉我我失踪了?或者这段代码如何通过组合实现?
你的例子可以通过这样的组合来实现:
class A {
private:
class B {
B(const B&) = delete;
B& operator=(const B&) = delete;
} b;
};
A
是不可复制的,因为它的成员 b
是不可复制的。
boost::noncopyable
没有真正的语义,这只是一个禁止孙子的实现细节。
class A : private boost::noncopyable {};
A
没有 boost::noncopyable
,因为 boost::noncopyable
在字面上和意义上都是空的。在这里,你会说“A
is noncopyable”,但在一般情况下,我总体上同意迈耶斯的观点。
您的示例仍然是 HAS-A 关系。
以class为例,大致相当于boost:noncopyable
:
class X {
private:
X(const X &);
X &operator=(const X &);
public:
X() {}
};
以下两个 class 具有相同的功能:
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
这个问题可以通过避免讨论特定示例的细节的方式来回答。继承 publicly 的 class 从定义其父级语义的所有内容开始 - 它的 public 函数,以及它的 public 状态变量,如果有的话。如果其中 none 被覆盖,它符合 Liskov substitution principle,并且应该以保留可替换性的方式覆盖这些属性是一个被广泛接受的设计原则。
对于私有继承,none 适用,除非程序员选择在派生的 class 中实现(或重新实现)所有 public 属性parent class,以一种保留可替代性的方式。由于 C++ 不需要私有派生 class 来实现其父级 public 方法和变量的版本,这与派生 class 而是包含父 class 的实例作为私有成员。特别是,对于私有继承,派生 class 在任何功能或操作方面都不是父类型的子类型,并且如果您的语言将派生 class 视为子类型,造成了误解和混淆的机会(尽管应该注意,除非您的语言有办法强制执行子类型的语义有效性(C++ 没有),否则这实际上是一种风格问题。)
根据我最喜欢的作者 Mr Scott Meyers 的说法,私有 继承和组合意味着相同的事情,即 Has-A 关系。因此,可以从组合中获得的一切(包含,当 class A 具有 class B 作为其成员时)都可以通过私有继承获得,反之亦然。
所以下面的代码应该是一个Has-A关系,但在我看来,它不是!
class A : private boost::noncopyable {.. this is irrelevant };
谁能告诉我我失踪了?或者这段代码如何通过组合实现?
你的例子可以通过这样的组合来实现:
class A {
private:
class B {
B(const B&) = delete;
B& operator=(const B&) = delete;
} b;
};
A
是不可复制的,因为它的成员 b
是不可复制的。
boost::noncopyable
没有真正的语义,这只是一个禁止孙子的实现细节。
class A : private boost::noncopyable {};
A
没有 boost::noncopyable
,因为 boost::noncopyable
在字面上和意义上都是空的。在这里,你会说“A
is noncopyable”,但在一般情况下,我总体上同意迈耶斯的观点。
您的示例仍然是 HAS-A 关系。
以class为例,大致相当于boost:noncopyable
:
class X {
private:
X(const X &);
X &operator=(const X &);
public:
X() {}
};
以下两个 class 具有相同的功能:
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
这个问题可以通过避免讨论特定示例的细节的方式来回答。继承 publicly 的 class 从定义其父级语义的所有内容开始 - 它的 public 函数,以及它的 public 状态变量,如果有的话。如果其中 none 被覆盖,它符合 Liskov substitution principle,并且应该以保留可替换性的方式覆盖这些属性是一个被广泛接受的设计原则。
对于私有继承,none 适用,除非程序员选择在派生的 class 中实现(或重新实现)所有 public 属性parent class,以一种保留可替代性的方式。由于 C++ 不需要私有派生 class 来实现其父级 public 方法和变量的版本,这与派生 class 而是包含父 class 的实例作为私有成员。特别是,对于私有继承,派生 class 在任何功能或操作方面都不是父类型的子类型,并且如果您的语言将派生 class 视为子类型,造成了误解和混淆的机会(尽管应该注意,除非您的语言有办法强制执行子类型的语义有效性(C++ 没有),否则这实际上是一种风格问题。)