Можно ли выполнить dynamic_cast из одного базового класса в другой? - PullRequest
5 голосов
/ 28 сентября 2010

Например, у меня есть такой код

class Base1
{
  virtual void wonderFULL() = 0;
};

class Base2
{
  // all this weird members
};

class Derived : public Base1, public Base2
{
  // not so weird members
};

int main()
{
  Derived Wonder;
  magicFunction(&Wonder);
  return 0;
}

void magicFunction(Base2 *ptr)
{
  if (Base1 *b1 = dynamic_cast<Base1 *>(ptr))
    b1->wonderFULL();
}

Однако wonderFULL никогда не выполняется из-за невозможности привести ptr к b1.Можно ли вообще выполнить такое преобразование?

Ответы [ 5 ]

7 голосов
/ 28 сентября 2010

Это

#include <iostream>

class Base1 {
public:
    virtual void wonderFULL() = 0;
};

class Base2 {
public:
    virtual ~Base2() {}                                       // added so the code compiles
};

class Derived : public Base1, public Base2 {
    virtual void wonderFULL() {std::cout << "wonderful\n";}   // added so the code compiles
};

void magicFunction(Base2 *ptr) {
    if (Base1 *b1 = dynamic_cast<Base1 *>(ptr))
        b1->wonderFULL();
}

int main() {
    Derived Wonder;
    magicFunction(&Wonder);
    return 0;
}

печатает wonderful для меня.Я пришел к выводу, что вы не показываете код, необходимый для воспроизведения вашей проблемы.

Возьмите (копию) вашего фактического кода и, удаляя ненужный код, шаг за шагом перегоняйте его, пока вы не получите автономный (не требующий никаких других заголовков, кроме std lib), компилируемый пример, который воспроизводитпроблема.Очень вероятно, что вы найдете проблему при этом.Однако, если вы этого не сделаете, у вас есть идеальный случай для репродукции, чтобы вернуться сюда и спросить.

2 голосов
/ 28 сентября 2010

У вас есть некоторые синтаксические ошибки, но ваша настоящая проблема в dynamic_cast не будет работать должным образом, если в ваших базовых классах нет хотя бы одной виртуальной функции.

Если вы сделаете так, как это выглядит:

class Base2
{
public:
  virtual ~Base2() {}
  // all this weird members
};

А затем исправьте другие ошибки: wonderFULL является личным и никогда не определяется.magicFunction объявляется после его использования.

Тогда все работает .

2 голосов
/ 28 сентября 2010

Вы можете создать иерархию, а затем отступить:

void magicFunction(Base2& ptr)
{
    try
    {
        Derived&  d = dynamic_cast<Derived&>(ptr);
        Base1&    b = dynamic_cast<Base1&>(d);
        b.wonderFULL();
    }
    catch(const std::bad_cast&)
    { /* Cast failed */ }
}
0 голосов
/ 28 сентября 2010

Я нашел проблему. Это было не о dynamic_casts. Я проверял неправильный объект, который не был унаследован от абстрактной базы. Спасибо.

0 голосов
/ 28 сентября 2010

Исходя из того, что я понимаю, то, как некоторые компиляторы C ++ организуют иерархию классов в памяти, должно быть возможно преобразование из одного базового класса в другой, но вы должны сначала привести к производному классу.Следовательно, вам нужно сделать что-то вроде:

Base1* b1 = dynamic_cast<Derived*>(ptr);

. Это приведет к приведению указанного указателя ptr к производному классу и затем неявным образом приведёт к другому указателю базового класса.

Однако другой более простой способ сделать это состоит в том, чтобы просто иметь метод в классе Base2, который возвращает указатель Base1, и производный класс может реализовать это сам без какого-либо хитрого кода.(Та же функция в Base2 может просто возвращать NULL, если вам не нужен чистый виртуальный класс).

...