dynamic_cast не работает

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

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

h файлы:

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)

Решение

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

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

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

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

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

РЕДАКТИРОВАТЬ: увидеть обновленный код

Я думаю, вам стоит хотя бы получить Derived from Base;) (я полагаю, что это опечатка)

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

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

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

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

Изменить: FYI, модифицированный код отлично работает с g ++ 3.4.5

Есть ли у вас какая-нибудь виртуальная функция в Base? Иначе не получится. По крайней мере, сделайте его dtor виртуальным.

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

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

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

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

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

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

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