钻石传承
Diamond inheritance
假设类 D 和 E 和 F 都继承自基类 B,并且 类 C 继承自 D 和 E。
(i( C类中出现了多少份B类?
(二( 使用虚拟继承将如何改变这种情况?解释 你的答案。
(iii(Java如何避免对许多人的多重继承的需求 的 在C++中可能使用多重继承的情况?
以下是我目前的一些想法,但我绝不是C++方面的专家!
(i)
如果 C 继承自 D 和 E 这两个 B 的子类,那么 D 和 E 在技术上是它们的超类的副本吗?那么如果 C 继承自 D 和 E,则意味着 C 中有 2 个 B 副本。
(ii)
使用虚拟有点类似于在Java中使用抽象(我认为(。现在考虑到这一点,这意味着 C 中不会有多个 B 副本,因为实例化将被级联到所需的级别。我不知道如何措辞我的解释,但说 B 有一个名为 print(( 的函数,它打印"我是 B",C 覆盖这个函数打印"我是 C"。如果你在没有 virtual 的情况下在 C 上调用 print((,你最终会打印 "i am B",使用 virtual 意味着它会打印 "i am C"。
(iii)
我的想法是Java可以使用接口来避免使用多重继承。您可以实现多个接口,但只能扩展一个类。我不确定这里还有什么要添加的,所以任何输入或相关资源都会有所帮助。
i(和(iii(是正确的。无论如何,根据我的经验,大多数时候C++当我使用多重继承时,这是因为基础是接口(这个概念在C++中没有关键字支持,但无论如何它都是你可以执行的概念(。
(ii(的第一句话是对的,但是你的第二句话说的是虚函数,这与虚拟继承完全不同。 虚拟继承意味着B
只有一个副本,并且D
和E
都有相同的副本作为它们的基础。在函数方面没有区别,但区别在于B
的成员变量(和基类(。
如果有一个函数打印出B
的成员变量foo
;那么在(ii(的情况下,这个函数总是打印相同的值,因为只有一个foo
,但是在(i(的情况下,从D
基类调用该函数可能会打印一个不同的值,从E
基类调用它。
"钻石继承"一词用两个词来概括这一切,作为一个很好的助记符:)
你似乎基本上已经得出了正确的答案,尽管推理需要努力。这里的关键问题是"如果 C 实例继承同一个基类两次,如何布局它的内存?
i( 对于 C 类型的对象,在内存布局中有 2 个基类 B 的副本。提供的示例是"钻石继承"的情况,因为当您绘制依赖/继承树时,您实际上是绘制钻石。钻石继承的"问题"本质上是询问如何在内存中布置对象。C++采用了两种方法,一种是快速的,复制数据成员,另一种是较慢的方法,即"虚拟继承"。采用非虚拟方法的原因是,如果你继承了一个没有数据成员的类(Java中的接口(,那么"复制数据成员"就没有问题,因为它们不存在(见我在底部的注释(。如果您的计划仅使用单个继承,则还建议使用非虚拟继承。
ii( 如果你有一个virtual class C
,那么这就是用C++语言表达的方式,你希望编译器执行英雄主义行为,以确保派生类的内存布局中只存在任何/所有基类的一个副本;我相信这也会导致轻微的性能下降。如果您现在使用"C"实例中的任何"B"成员,它将始终引用内存中的同一位置。请注意,虚拟继承与函数是否为虚拟函数无关。
旁白:这也与抽象类的概念完全无关。要在C++中使类抽象,请设置任意方法声明 = 0,如 void foo() = 0;
;对任何方法(包括析构函数(这样做就足以使整个类抽象。
iii(Java完全禁止它。在Java中,只有单个继承以及实现任意数量接口的能力。虽然接口确实授予您"is-a"关系和具有虚函数的能力,但它们隐含地避免了C++在数据布局和菱形继承方面遇到的问题,因为接口不能添加任何数据成员,事实上:对于如何解析任何数据成员的位置没有混淆。
iii的一个重要扩展是意识到,如果你碰巧"实现同一个接口两次",虚拟函数调用调度根本不会受到影响。原因是该方法将始终执行相同的操作,即使虚拟表中有多个副本也是如此;它只作用于类的数据,它本身不包含需要消除歧义的数据。
- 什么是钻石问题?是一系列问题还是特定问题?
- 钻石继承虚拟成员铸造与指针
- 接口的钻石继承(C++)
- 在钻石问题的求解中,为什么要虚拟地继承两次grand-parent类
- C++如何解决钻石问题?
- c++ 中的函数重载如何在没有钻石继承的情况下工作?
- 多个虚拟(钻石)继承
- C++解决没有虚拟继承的钻石继承问题
- 多种继承C 的钻石问题
- 如何调用所有基本类的复制构造函数,以在C 中复制钻石继承中最派生的类对象
- 假设钻石继承打破了C++的封装是否正确?
- C++多个钻石继承和纯虚函数
- 如何解决钻石问题的这种歧义
- 解决QT类的特定C 钻石问题
- 在C++中尝试基于用户确定的宽度打印钻石
- 学习传承
- 虚拟继承如何解决 c++ 中的多重继承(钻石)?它将走哪条路
- 首选钻石继承中一个类的变量
- C++ 钻石般的传承
- 钻石传承