为啥我不能在多重继承期间动态转换“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_casts 在转换为引用类型时会被抛出,如果您要转换为指针类型 (coliru.stacked-crooked.com/a/84ef0c302f8097d5),您会得到 nullptr【参考方案2】:

假设Bar 应该从Foo 继承(在当前示例中没有),您在此处看到的问题通常称为diamond problem。您要使用哪个版本的fooBar::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”?的主要内容,如果未能解决你的问题,请参考以下文章

多重继承下的类型转换

为啥要使用接口,多重继承与接口,接口的好处?

为啥大多数编程语言不支持多重继承?

为啥在多重继承的情况下QObject需要是第一个

虚拟多重继承和强制转换

转换为多重继承