Jac*_* V. 23 c++ oop inheritance
如果你有一个使用公共继承实现的继承关系,并且有一个继承的钻石你会有类似的东西:
在这种情况下,如在标准库(?)中使用的那样,在iostream既是-a istream又是-o ostream的情况下,istream isa-a stream而ostream是-stream,而且它们是相同的流,流中的任何函数,应用于iostream是有意义的,应该处理相同的底层结构.
在C++中,为了能够共享istream和ostream中的流副本,它必须由它们虚拟地继承.
但是,如果您愿意,则无法虚拟继承,并且每次引用基类的成员时,请指定所需的两个副本(istream中的一个或ostream中的一个)(通过强制转换或使用范围) ::等等).
我的问题是,[编辑:有没有其他情况]除了"这不是一个真正的关系,我使用naughtily使用的公共继承作为语法上的方便,当它在概念上没有"或"我从来没有需要从最派生的类中多态地引用基类,因此非常小的开销是不值得的",有任何理由它在概念上有效继承非虚拟的并且有两个基类副本,一个为每个姐妹中级班?
让我们来看一个简单的例子。
   B           B1   B2
   |             \ /
   D              D
在左侧,我们发现一个源自单个低音的类。在 OO 设计中,存在尊重 Liskov 替换原则的 is-a 关系显然是合理的。
右侧,B1和B2都是 , 的独立基D,并且D可以使用B1*or B2*(或引用)进行多态访问。希望我们能够接受这也是一个有效的 OO 设计(尽管 Sun 认为这对 Java 程序员来说压力太大,令人费解;-P)。B1然后考虑从和中提取一些基本功能B2并使其可重用:假设它们都对任意数字列表进行操作,并且可以合理地授予这些数字的直接/public访问权限:
   Container<int>   Container<int>
              \     /
              B1   B2
                \ /
                 D
如果这还没有点击,也许:
   Container<int>   Container<int>
              \     /
            Ages  Heights
                \ /
             Population
说 is Ages-a是合理的Container<int>,尽管它可能会添加一些方便的功能,例如average, min, max, num_teenagers。与 相同Heights,可能具有一组不同的便利功能。显然 aPopulation可以合理地替换 anAges或Heights集合(例如size_t num_adults(Ages&); if (num_adults(my_population)) ...)。
这里的要点是,每个支持容器并不意味着与进一步派生的类(例如Population; )具有 1:1 的关系。相反,它与其直接派生类完全是 1:1。
再次强调,使用组合还是继承是接口设计的决定,但以这种方式公开暴露容器并不一定是无效的。(如果担心维护Population不变量,例如在成员函数为 时可能会创建Ages::empty() == Heights::empty()数据变异函数。)Container<int>protectedconstpublic
正如您所观察到的,Population没有明确的 is-a 关系,Container<int>并且代码可能需要显式消歧。那是合适的。当然,如果它存储一些其他数字集,则Population派生也是可能且合理的Container<int>,但这将独立于间接继承的容器。
我的问题是,除了“这并不是真正的 is-a 关系,当它在概念上无效时,我顽皮地使用公共继承作为语法便利”
我认为上述 is-a 关系或概念有效性没有问题,如果你这样做,请解释一下......
“我从来不需要从最派生的类中多态地引用基类,因此难以置信的小开销是不值得的”
我认为很明显我只是基于自然对象关系进行数据建模,而不是一些可疑的优化。从基类中分解出来的支持容器类是实际使用的,并且在每个类中必须是独立的。