Why can't I dynamic_cast “sideways” during multiple inheritence?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-17 17:10:08

问题


The following code throws 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;
}

I remember once reading how dynamic_cast has implementation performance trade-offs because "it traverses the full inheritence lattice" in order to evaluate correctly. What the compiler needs to do here is first cast up and then down again.

Is it possible to make the above work or do I need to add virtual Foo* Bar::as_foo()=0; ?


回答1:


There are no virtual functions in Foo, so dynamic_cast is perfectly obliged to fail. There needs to be a virtual function. It's also a bad idea to do so during construction, as you're going to run into construction order issues.




回答2:


Assuming that Bar should inherit from Foo (which it does not in the current example), the problem you're seeing here is commonly refered to as the diamond problem. Which version of foo do you want to use, the Bar::foo() or the Foo::foo()? You're going to need to specify a virtual inheritance:

struct Foo{
    ~virtual Foo(){}
     void foo(){}
};

struct Bar : virtual public Foo

struct Baz : virtual public Foo, public Bar

to let it know that there should only exist one type of foo(). Hence, virtual inheritance is used to invoke the call to foo() within the constructor.

Edit:

And to be clear, I am assuming you want Bar to inherit from Foo. If you don't have that in your code then that's the cause of the bad cast error. There's no inheritance hierarchy for Bar to traverse to get to Foo. Also, modern compilers shouldn't even compile without the virtual inheritance but certain legacy compilers will happily @#$#$ it up.

And if I'm going to comment on another answer, I better follow through with my own answer!




回答3:


There are a couple of things wrong in your example, perhaps it's an accident?

Bar does not inherit from Foo, so it cannot be cast down to Foo in the constructor of Bar. They also do not share a common inheritance parent, and therefore cannot be cast between each other (sideways). What you probably want is:

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 
}

Hope this helps! If you need clarifications, please ask!




回答4:


Constructing a Baz involves constructing its bases, and one of those is a Bar. The Bar base of the Baz is not castable to Foo, even if the final Baz should be.



来源:https://stackoverflow.com/questions/4641398/why-cant-i-dynamic-cast-sideways-during-multiple-inheritence

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!