为啥我不能在多重继承期间动态转换“sideways”?
Posted
技术标签:
【中文标题】为啥我不能在多重继承期间动态转换“sideways”?【英文标题】:Why can't I dynamic_cast "sideways" during multiple inheritence?为什么我不能在多重继承期间动态转换“sideways”? 【发布时间】:2011-01-09 19:56:43 【问题描述】:以下代码抛出 std::bad_cast
struct Foo
void foo ()
;
struct Bar
Bar ()
dynamic_cast <Foo &> (*this) .foo ();
virtual ~ Bar ()
;
struct Baz : public Foo, public Bar
;
int main ()
Baz b;
我记得有一次阅读 dynamic_cast 如何权衡实现性能,因为“它遍历完整的继承格”以便正确评估。编译器在这里需要做的就是先向上投射,然后再向下投射。
是否可以使上述工作或我需要添加
virtual Foo* Bar::as_foo()=0;
?
【问题讨论】:
不是lattice
。向上/向下继承树。
@Martin,在这个例子中它是一棵树,但 C++ 继承更普遍的是一个有向图而不是一棵树。 @spraff:我想你想要一个 down 先投到Baz
,然后是 up 投。
【参考方案1】:
Foo 中没有虚函数,因此 dynamic_cast 完全有可能失败。需要有一个虚函数。在施工期间这样做也是一个坏主意,因为您会遇到施工订单问题。
【讨论】:
"Foo 中没有虚函数" 这有什么关系? @curiousguy 您只能在多态对象上使用dynamic_cast
(或者,根据您的经验,您会得到bad_cast
异常)。一个对象只有在其类型至少有一个虚函数时才是多态的。
@rubenvb "根据你的经验,你会得到一个 bad_cast 异常" 不,你什么也得不到!
@curiousguy 对。我的错。 bad_cast
s 在转换为引用类型时会被抛出,如果您要转换为指针类型 (coliru.stacked-crooked.com/a/84ef0c302f8097d5),您会得到 nullptr
。【参考方案2】:
假设Bar
应该从Foo
继承(在当前示例中没有),您在此处看到的问题通常称为diamond problem。您要使用哪个版本的foo
,Bar::foo()
还是Foo::foo()
?您将需要指定一个虚拟继承:
struct Foo
~virtual Foo()
void foo()
;
struct Bar : virtual public Foo
struct Baz : virtual public Foo, public Bar
让它知道应该只存在一种类型的foo()
。因此,virtual inheritance 用于在构造函数中调用对foo()
的调用。
编辑:
为了清楚起见,我假设您希望 Bar
继承自 Foo
。如果您的代码中没有它,那么这就是错误转换错误的原因。 Bar
没有继承层次结构可以遍历以到达 Foo
。此外,现代编译器甚至不应该在没有虚拟继承的情况下进行编译,但某些旧版编译器会很高兴地@#$#$ 它。
如果我要对另一个答案发表评论,我最好按照自己的答案继续!
【讨论】:
也许我遗漏了一些东西,但 Bar 根本没有从 Foo 继承。除非你认为这是一个错字 @Falmarri 我是,你看到的是我快速编辑的第一个版本。 这与钻石问题无关。 "struct Baz : virtual public Foo, public Bar
" 为什么要在这里写virtual public Foo
?【参考方案3】:
您的示例中有几处错误,也许是意外?
Bar 不继承自 Foo,因此不能在 Bar 的构造函数中向下转换为 Foo。它们也不共享一个共同的继承父级,因此不能在彼此之间进行转换(横向)。你可能想要的是:
struct withFoo
virtual void foo ()
virtual ~withFoo()
;
struct Foo : public virtual withFoo
;
struct Bar : public virtual withFoo
Bar ()
foo(); // no need to cast!
;
struct Baz : public Foo, public Bar
;
int main ()
Baz b;
b.foo(); // because of virtual inheritance from withFoo, there is no ambiguity here
希望这会有所帮助!如果您需要澄清,请询问!
【讨论】:
你忘记了withFoo
中的虚拟析构函数。
@wheaties 谢谢!我确实有!【参考方案4】:
建造一个 Baz 涉及建造它的基地,其中之一就是酒吧。 Baz 的 Bar 基础不能转换为 Foo,即使最终的 Baz 应该是。
【讨论】:
以上是关于为啥我不能在多重继承期间动态转换“sideways”?的主要内容,如果未能解决你的问题,请参考以下文章