- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
如果你有通过公共(public)继承实现的 is-a 继承关系,并且有一个菱形继承,你会得到类似的东西:
在这种情况下,正如在标准库 (?) 中使用的那样,在 iostream 既 is-a istream 和 is-ostream 的范围内,istream is-a 流和 ostream is-a 流,而且它们是 相同的 流,流中的任何函数,适用于 iostream,都应该处理相同的底层结构。
在C++中,为了共享istream和ostream中stream的拷贝,必须虚拟继承。
但是,如果您愿意,您可以不虚拟继承,并且每次引用基类的成员时,指定两个拷贝中的哪一个(一个在 istream 中或一个在 ostream 中)想要(通过强制转换或使用 scope::blah)。
我的问题是,[编辑:是否有任何其他情况]除了“这不是真正的 is-a 关系,当它在概念上无效时,我顽皮地使用公共(public)继承作为语法便利”或“我永远不需要从最派生的类中多态地引用基类,因此非常小的开销是不值得的”,有任何理由非虚拟继承并拥有两个基类拷贝在概念上是有效的类,每个姐妹中间类一个?
最佳答案
我们来看一个简单的例子。
B B1 B2
| \ /
D D
在左边,我们发现了一个派生自单个低音的类。在 OO 设计中,具有尊重 Liskov Substitution Principal 的 is-a 关系显然是合理的。
在右边,两个 B1
和 B2
是 D
的独立基, 和 D
可以使用 B1*
进行多态访问或 B2*
(或引用)。希望我们可以接受这也是一种有效的 OO 设计(尽管 Sun 认为它对 Java 程序员来说压力太大了;-P)。然后考虑从 B1
中排除一些基本功能。和 B2
并使其可重用:假设它们都在任意数字列表上进行操作,它们可以合理地直接授予/public
访问:
Container<int> Container<int>
\ /
B1 B2
\ /
D
如果这还没有点击,也许:
Container<int> Container<int>
\ /
Ages Heights
\ /
Population
按理说Ages
是一个 Container<int>
,尽管它可能会添加一些方便的功能,例如 average
, min
, max
, num_teenagers
. Heights
相同,可能具有不同的便利功能。显然是 Population
可以合理地替换为 Ages
或 Heights
集合(例如 size_t num_adults(Ages&); if (num_adults(my_population)) ...
)。
这里的重点是,每个支持容器并不意味着与进一步派生的类(如 Population
)具有 1:1 的关系。 ;相反,它的意思是与其直接派生的类完全是 1:1。
同样,使用组合还是继承是接口(interface)设计决定,但以这种方式公开公开容器不一定无效。 (如果担心维护 Population
不变量,例如 Ages::empty() == Heights::empty()
,可以将 Container<int>
的数据变异函数设为 protected
而 const
成员函数为 public
。)
如您所见,Population
与 Container<int>
没有明确的 is-a 关系并且代码可能需要明确的消歧。那是合适的。当然,Population
也是可能的,也是合理的。源自 Container<int>
如果它存储了一些其他数字集,但这将独立于间接继承的容器。
My question is, other than "This isn't really an is-a relationship, I used naughtily used public inheritance as a syntactic convenience when it wasn't conceptually valid"
我认为上述的 is-a 关系或概念有效性没有任何问题,如果你这样做,请解释......
"I never need to refer polymorphically to the base class from the most-derived class so the incredibly small overhead isn't worth it"
我认为很明显我只是在基于自然对象关系进行数据建模,而不是一些可疑的优化。从基础中分解出来的支持容器类是实际使用的,并且必须在每个基础中独立。
关于c++ - 如果您使用多个 is-a 继承,您是否不想使用相互基类的虚拟继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5388667/
我是一名优秀的程序员,十分优秀!