gpt4 book ai didi

c++ - 可以接受使用虚拟继承来防止意外创建钻石吗?

转载 作者:行者123 更新时间:2023-11-30 01:32:38 26 4
gpt4 key购买 nike

这是对一些真实代码的简化,当我没有意识到其他人已经实现了 Foo 并从中派生时,我犯了一个真正的错误。

#include <iostream>

struct Base {
virtual ~Base() { }
virtual void print() = 0;
};

struct OtherBase {
virtual ~OtherBase() { }
};

struct Foo : public Base { // better to use virtual inheritance?
virtual void print() { std::cout << "Foo" << std::endl; };
};

struct Bar : public Base { // better to use virtual inheritance?
virtual void print() { std::cout << "Bar" << std::endl; };
};

// The design is only supposed to implement Base once, but I
// accidentally created a diamond when I inherited from Bar also.
class Derived
: public OtherBase
, public Foo
, public Bar // oops.
{
};

int main() {
Derived d;
OtherBase *pO = &d;

// cross-casting
if (Base *pBase = dynamic_cast<Base *>(pO))
pBase->print();
else
std::cout << "fail" << std::endl;
}

编辑:让您不必运行此代码...

  • 如果按原样运行,它会打印“失败”(不受欢迎,难以调试)。
  • 如果您删除标记为“oops”的行,它会打印“Foo”(期望的行为)。
  • 如果您留下“哎呀”并将两个继承虚拟化,它将无法编译(但至少您知道要修复什么)。
  • 如果您删除“oops”并将它们设为虚拟,它将编译并打印“Foo”(期望的行为)。

对于虚拟继承,结果要么是好的,要么是编译器错误。如果没有虚拟继承,结果要么是好的,要么是无法解释的、难以调试的运行时故障。


当我实现 Bar 时,它基本上复制了 Foo 已经在做的事情,它导致动态转换失败,这在实际代码中意味着不好的事情。

起初我很惊讶没有编译器错误。然后我意识到没有虚拟继承,这会在 GCC 中触发“没有唯一的最终覆盖程序”错误。我故意选择不使用虚拟继承,因为在这个设计中不应该有任何菱形。

但是,如果我在从 Base 派生时使用了虚拟继承,那么代码将同样有效(没有我的糟糕),并且我会在编译时收到钻石警告,而不必在运行时追踪错误时间。

所以问题是——您认为使用虚拟继承来防止将来犯类似错误是否可以接受?在这里使用虚拟继承没有充分的技术理由(我可以看到),因为设计中永远不应该有菱形。它只会在那里强制执行该设计约束。

最佳答案

这不是个好主意。

虚拟继承只有在事先计划好的情况下才会使用。正如您刚刚发现的,在许多情况下,所有后代类都必须知道它。如果基类有一个非默认构造函数,您必须担心它总是由叶类构造的事实。

哦,除非自从我上次查看以来情况发生了变化,否则在没有基类帮助的情况下,您不能将虚拟基类向下转换为任何派生类。

关于c++ - 可以接受使用虚拟继承来防止意外创建钻石吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1402384/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com