复杂的钻石问题:C++虚拟继承
Complex diamond issue: C++ virtual inheritance
我有一个钻石问题,看起来像这样:
__ A
/ |
| B |
v|/v v|v v
B2 B3 C
v /v /
B4 /
/
D
我尝试了很多方法来制作最好的虚拟继承以获得没有重复项,但我找不到解决方案。类 A 包含一个位置。下面是一个示例输出:
Call: A() position pointer is: 0x2203be8
Call: B()
Call: B2() position pointer is: 0x2203be8
Call: B3() position pointer is: 0x2203be8
Call: C() position pointer is: 0x2203a28
Call: B4() position pointer is: 0x2203be8
Call: D() position pointer is: 0x2203a28
为什么 D 和 C 没有相同的位置指针?为什么这个 A::p osition 没有构造函数?我应该进行什么虚拟继承来解决这个问题?谢谢。
编辑:
下面是一个代码示例:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;
编辑2: 为了进行输出,我将以下代码放在每个构造函数中:
A::A()
{
std::cerr << "Call: A() position pointer is: " << &_position << std::endl;
}
既然你说下面的代码(适用于我的实现)对你来说已经坏了,那么显然代码不是问题。问题出在您的设置中的其他内容上;也许是编译器错误。您应该缩小可能导致问题的其他原因;由于代码本身被排除为问题,也许最好的下一步是更新编译器。
无论如何,这使得这个问题相当特定于您的设置。如果您确实找到了可能适用于其他人的解决方案,那么您应该回来发布它。在那之前,我投票结束这个问题。
我正在尝试重现您的问题。这是我使用的代码:
#include <iostream>
struct A { int a; };
struct B { int b; };
struct B2 : virtual B, virtual A {};
struct B3 : virtual B, virtual A {};
struct B4 : virtual B2, virtual B3 {}; // these virtuals are unnecessary in this case...
struct C : virtual A {};
struct D : B4, C {};
int main() {
D d;
std::cout << &((B4*)&d)->a << 'n';
std::cout << &((B3*)(B4*)&d)->a << 'n';
std::cout << &((B2*)(B4*)&d)->a << 'n';
std::cout << &((A*)(B2*)(B4*)&d)->a << 'n';
std::cout << &((A*)(B3*)(B4*)&d)->a << 'n';
std::cout << &((C*)&d)->a << 'n';
std::cout << &((A*)(C*)&d)->a << 'n';
}
但是我得到的结果符合预期,其中每个对象的a
成员都是相同的。如果我在构造函数中也使用打印地址,我会得到相同的结果:http://ideone.com/8FdQ1O
如果我稍作更改并从 C 的定义中删除virtual
关键字:
...
struct C : A {};
...
(使用构造函数的版本)
那么我确实看到了你描述的问题,C 有自己的 A 子对象,与 B2、B3 和 B4 使用的虚拟对象不同。
您确定在所有需要的地方都使用了virtual
关键字吗?您显示的结果似乎表明您在某处错过了它。我还注意到,您显示的输出与您显示的代码片段反映的构造函数顺序不同;输出首先显示 A(),但代码指示应首先执行 B()。
继承的工作方式是,大多数派生类型将包含每个类型的单个虚拟子对象,该子对象实际上继承在继承树中的任何位置。此外,派生最多的类型将包含每个非虚拟继承实例的子对象:
struct A {};
struct B : virtual A {};
struct C : A, B {};
struct D : virtual A, C {};
struct E : A, D {};
struct F : virtual A, E {};
struct G : A, F {};
G g;
g
总共包含四个A
子对象;每次A
非虚拟继承时(C
、E
和G
)一个,A
虚拟继承的所有时间(B
、D
和F
)一次。
你目前有什么代码? 看起来解决方案将是:
class D;
class C : public virtual D;
class B4 : public virtual D;
class B2 : public virtual B4;
class B3 : public virtual B4;
class B : public B2, public B3;
class A : public B2, public B3, public C;
基于您的图表。 如果我读错了,A 是基础,而不是 D。 那么它需要看起来像这样:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;
为什么 D 和 C 没有相同的位置指针?
因为您实际上是从 B4 和 C 继承 D。这意味着您有两个 A 副本(和两个指针)。
在 D 构造函数中 &B4::p osition 不同于 &C::p osition
为什么这个 A::p osition 没有构造函数?
不知道,您的 A 类是否有可能有多个构造函数,并且 C::C() 调用默认静默构造函数?
我应该进行什么虚拟继承来解决这个问题?
让一切变得虚拟。这意味着您需要从 D::D() 显式调用每个构造函数(即
A::A(),B::B(),B2::B2(),B3::B3(),C::C() )。Tbh 我认为你应该重新考虑你的等级制度。我不知道细节,但似乎您的问题通过组件设计得到了更清晰的解决方案。
- 虚拟决赛作为安全
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- 如何在C++中获得"静态纯虚拟"功能?
- C++无法定义虚拟函数 OUTER 类和头文件
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 大小虚拟继承中的派生类
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 使用 C++ 和 i2c 工具从虚拟 i2c 写入和读取
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- std::is_trivially_copyable_v 关于虚拟功能
- 删除C++继承中虚拟类成员的代码重复
- 子类地址等于虚拟基类地址?
- 当覆盖存在时调用基本虚拟"binded to object"函数
- 用于创建/注册虚拟存储设备的 IOKit 驱动程序
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?