dynamic_cast вызывает нарушение сегментации в случае трехуровневого наследования

Кажется, что dynamic_cast не работает в случае трехуровневого наследования.

Приложение вылетает с ошибкой сегментации (ядро сброшено) в точке print() вызов метода (в main()).

Вот код:

#include <iostream>
#include <typeinfo>     //must be included to call any member functions for the typeinfo object returned by typeid()
using namespace std;
class CBase
{
public:
virtual void print()
{
cout<<"CBase::print"<<endl;
}
virtual ~CBase()
{ }
};
class CDerivedA : public CBase
{
public:
virtual void print()
{
cout<<"CDerivedA::print"<<endl;
}
virtual ~CDerivedA()
{}
};
class CDerivedB : public CDerivedA
{
public:
void print()
{
cout<<"CDerivedB::print"<<endl;
}
};
int main()
{
CBase* ptrB = new CDerivedA();
CDerivedB* ptrDB = dynamic_cast<CDerivedB*>(ptrB);
ptrDB->print();
return 1;
}

0

Решение

«Указатель, который указывает на CDerivedA» (базовый класс), не может быть приведен к «указателю на CDerivedB» (производный класс). Обратите внимание, что я не имею в виду объявленный тип указателя; проблема в том, что реальный объект указывает на на самом деле является экземпляром базового класса, таким образом, удрученный не может преуспеть.

dynamic_cast возвращает nullуказатель в случае неудачного понижения, что может быть причиной нарушения сегментации (в случае приведения ссылки он выдаст bad_cast исключение).

Обратите внимание, что dynamic_cast требует RTTI (информация о типе времени выполнения), чтобы работать правильно. RTTI может быть отключен в компиляторе по соображениям производительности (поскольку он включает некоторые накладные расходы во время выполнения, если он включен). Пожалуйста, проверьте, что в вашем компиляторе включен RTTI.

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

Основы Даункинг

Вы не можете опустить экземпляр базового класса. Вы можете уменьшить указатель, объявленный как «pointer-to-base-class», который фактически указывает на экземпляр производного класса. Пример того, как вы можете использовать downcasting:

class Base
{ public:
virtual void baseMethod() {cout<<"baseMethod in Base"<<endl;}
// I am omitting virtual destructors here for brevity,
// which you should _not_ do in your code!
}
class Derived : public Base
{ public:
void baseMethod() {cout<<"baseMethod in Derived"<<endl;}
virtual void derivedMethod(){cout<<"derivedMethod in Derived"<<endl;}
}
class Derived2 : public Derived
{ public:
void baseMethod() {cout<<"baseMethod in Derived2"<<endl;}
void derivedMethod(){cout<<"derivedMethod in Derived2"<<endl;}
void derived2Method(){cout<<"derived2Method in Derived2"<<endl;}
}

void someFunction(Base* pBase)
{
// pBase may actually point to an instance of Base, Derived or Derived2.
// But you can invoke only 'baseMethod' on pBase,
// since 'derivedMethod' and 'derived2Method' are not declared in Base.

pBase->baseMethod(); // ok

// ERROR: pBase->derivedMethod();
// ERROR: pBase->derived2Method();

// To invoke 'derivedMethod', you have to downcast to Derived:
Derived* pDerived = dynamic_cast<Derived*>(pBase);
if(pDerived /* != null */)
{
// Downcast successful, i.e.
// pBase actually points to an instance of Derived _or_ Derived2.
// Both have the 'derivedMethod', so you can invoke it via 'pDerived' pointer:

pDerived->derivedMethod(); // ok

// ERROR: pDerived->derived2Method();

// To call 'derived2Method', you have to downcast to Derived2.
}
else
{
// If we are here, then dynamic_cast returned null,
// i.e. the downcast was NOT successful
// and pBase actually points to an instance of Base.
}

}

Избегайте бросков

Вы должны попытаться разработать свою программу так, чтобы приведения не были необходимы.
Используйте вместо этого полиморфизм.
Объявите все необходимые методы в базовых классах. использование чисто виртуальные методы.

Обновление базы до производной

Ты не можешь Обновить экземпляры через кастинг.
Если вы хотите обновить экземпляр Base к примеру Derived,
тогда вы должны определить конструктор в Derived который принимает Base в качестве аргумента и создает новый экземпляр Derived через new, Обратите внимание, что старый экземпляр Base остается, как это было, только новый экземпляр Derived создано.

class Derived : public Base
{ public:

Derived(Base& base)
: Base(base) // use copy constructor of Base
{
// initializations specific to Derived
}

// ... other methods ...
}// Usage:
Base* pBase = new Base();
Derived* pDerived = new Derived(*pBase); // "upgrade" Base to Derived.

// The instance of Base (pointed to by pBase) still lives,
// and a new instance of Derived (pointed to by pDerived) is born.

// Do not forget to delete both pBase and pDerived!

Надеюсь, это поможет.

Большое спасибо Тадеуш Копец для исправления.

4

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector