Почему я не могу dynamic_cast "в сторону" во время множественного наследования? - PullRequest
2 голосов
/ 09 января 2011

Следующий код выдает 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;?

Ответы [ 4 ]

7 голосов
/ 09 января 2011

В Foo нет виртуальных функций, поэтому dynamic_cast совершенно обязан завершиться с ошибкой Там должна быть виртуальная функция. Это также плохая идея сделать это во время строительства, так как вы столкнетесь с проблемами в строительном заказе.

2 голосов
/ 09 января 2011

Предполагая, что Bar должно наследоваться от Foo (чего нет в текущем примере), проблему, которую вы здесь видите, обычно называют проблема алмаза . Какую версию foo вы хотите использовать, Bar::foo() или Foo::foo()? Вам нужно указать виртуальное наследование:

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

struct Bar : virtual public Foo

struct Baz : virtual public Foo, public Bar

, чтобы сообщить ему, что должен существовать только один тип foo(). Следовательно, виртуальное наследование используется для вызова вызова foo() в конструкторе.

Edit:

И чтобы быть ясным, я предполагаю, что вы хотите, чтобы Bar унаследовал от Foo. Если в вашем коде этого нет, то это является причиной ошибки неверного приведения. Не существует иерархии наследования, которую Bar должен пройти, чтобы добраться до Foo. Кроме того, современные компиляторы не должны даже компилироваться без виртуального наследования, но некоторые унаследованные компиляторы с радостью это сделают.

И если я собираюсь комментировать другой ответ, мне лучше довести свой ответ до конца!

1 голос
/ 09 января 2011

В вашем примере есть пара ошибок, возможно, это случайность?

Бар не наследуется от Foo, поэтому его нельзя преобразовать в Foo в конструкторе Bar. Они также не имеют общего родителя наследования и поэтому не могут быть разыграны друг с другом (в сторону). Что вы, вероятно, хотите, это:

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 
}

Надеюсь, это поможет! Если вам нужны разъяснения, пожалуйста, спросите!

0 голосов
/ 10 января 2011

Построение база включает в себя строительство его баз, и одна из них является бар.Базовая база Баз не подлежит касту в Фу, даже если финальный Баз должен быть.

...