Кажется, что 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;
}
«Указатель, который указывает на 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!
Надеюсь, это поможет.
Большое спасибо Тадеуш Копец для исправления.
Других решений пока нет …