dynamic_cast не работает - PullRequest
       28

dynamic_cast не работает

5 голосов
/ 26 февраля 2009

У меня есть базовый класс и производный класс. У каждого класса есть файл .h и файл .cpp.

Я выполняю dynamic_cast объекта базового класса для производного класса в следующем коде:

ч файлов:

class Base
{
  public:
    Base();
    virtual ~Base();
};

class Derived : public Base
{
  public:
    Derived(){};
    void foo();
};

class Another
{
  public:
    Another(){};
    void bar(Base* pointerToBaseObject);
};

cpp файлы:

Base::Base()
{
    //do something....
}
Base::~Base()
{
    //do something....
}
void Derived::foo()
{
    Another a;
    a.bar(this);
}
void Another::bar(Base* pointerToBaseObject)
{
    dynamic_cast<Derived*>(pointerToBaseObject)
}

По какой-то странной причине произойдет сбой приведения (возвращает NULL). Однако приведение завершится успешно, если я перенесу реализацию конструктора класса Derived из .h в файл .cpp.

Что может быть причиной?

Компилятор - gcc 3.1, в Linux-SUSE. Кстати, я вижу это поведение только на этой платформе, и тот же код прекрасно работает в Visual Studio.

Ответы [ 6 ]

7 голосов
/ 26 февраля 2009

Есть ли у вас какие-либо виртуальные функции в базе? Это не будет работать иначе. Если ничего другого, сделайте его виртуальным.

Не знаю, спрашивал ли его уже тот парень, который удалил свой ответ, но я думаю, что это было что-то другое: вы делаете dynamic_cast из конструктора баз? Если так, это не сработает. Компилятор будет думать, что Base - это наиболее производный тип, аналогичный тому, когда вы вызываете виртуальную функцию, и он в конечном итоге вызывает версию Base.

5 голосов
/ 26 февраля 2009

Код в том виде, в котором он был опубликован, не должен завершаться сбоем, если у вас есть виртуальная функция в базовом классе (как указано в значке litb)

Но я считаю, что каждый текущий компилятор генерирует ошибку типа «Базовый класс не полиморфный», если у вас ее нет, так что, вероятно, это не будет проблемой.

Единственное, о чем я могу подумать, это то, что из-за какой-то странной ошибки все становится встроенным и не генерируется vtable. Но если вы поместите конструктор в файл C ++, компилятор решит не вставлять все подряд, запустив создание vtable, заставив работать ваш привод.

Но это очень дикая догадка, и я не думаю, что какой-либо компилятор мог бы допустить такую ​​ошибку (?)

Если вы хотите получить определенный ответ, напишите больше кода. И используемый компилятор / платформа.

РЕДАКТИРОВАТЬ: Просмотр обновленного кода

Я думаю, что вы должны по крайней мере получить производное от базы;) (Полагаю, это опечатка)

Но, увидев код, я могу думать только о том, что gcc (неправильно) вставляет все и не генерирует vtable для Derived. Для чего это стоит, это прекрасно работает скомпилирован с GCC 4.0

3.1 уже исполнилось 7 лет ... если бы была возможность обновить, я бы пошел на это.

3 голосов
/ 26 февраля 2009

Сделайте деструктор виртуальным и поместите его (или хотя бы один виртуальный метод) в файл .cpp.

Некоторые компиляторы (читай: gcc) ищут первое обнаруженное не встроенное тело виртуального метода и используют его, чтобы решить, куда поместить таблицу виртуальных методов. Если у вас нет виртуальных методов с телами в файле .cpp, таблица виртуальных методов не создается.

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

Если у вас есть класс, который вы ожидаете получить подклассом, и у него есть деструктор, или если у класса есть какие-либо переменные экземпляра, которые являются классами с деструкторами, то вы действительно захотите сделать свой деструктор виртуальным (даже если он имеет пустое тело). В противном случае ожидаемая очистка не будет выполняться для экземпляров подкласса.

0 голосов
/ 26 февраля 2009

В опубликованном вами коде Derived не является производным от Base.

Редактировать: К вашему сведению, модифицированный код отлично работает с g ++ 3.4.5

0 голосов
/ 26 февраля 2009

При просмотре вашего кода я не вижу наследства. Вы забыли это сделать? Производное ничего не происходит.

0 голосов
/ 26 февраля 2009

Вы делаете это в Visual C ++? Я думаю, что вы используете для настройки информации о типе среды выполнения (RTTI) в настройках компилятора.

Пожалуйста, не сердите меня, если я ошибаюсь. Прошло много времени с тех пор, как я использовал C ++ !!!

...