dynamic_cast терпит неудачу

У меня есть базовый класс и производный класс. У каждого класса есть файл .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). Однако приведение будет успешным, если я перенесу реализацию конструктора производного класса из .h в файл .cpp.

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

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


person Igor Oks    schedule 26.02.2009    source источник
comment
может быть, это ошибка gcc 3.1? попробуйте опцию -fdump-class-hierarchy и посмотрите, создает ли она виртуальную таблицу для ваших двух классов   -  person Johannes Schaub - litb    schedule 26.02.2009


Ответы (6)


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

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

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

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

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

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

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

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

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

person Pieter    schedule 26.02.2009

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

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

person Johannes Schaub - litb    schedule 26.02.2009
comment
У меня есть виртуальные функции в Base. - person Igor Oks; 26.02.2009

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

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

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

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

person Mr Fooz    schedule 26.02.2009

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

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

person Sean    schedule 26.02.2009

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

person plinth    schedule 26.02.2009

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

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

person Community    schedule 26.02.2009