سؤال

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; ?

هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

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!

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!

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top