C++ 在三级继承的情况下,动态_cast会导致分段冲突

C++ 在三级继承的情况下,动态_cast会导致分段冲突,c++,inheritance,dynamic-cast,polymorphism,C++,Inheritance,Dynamic Cast,Polymorphism,在三级继承的情况下,dynamic\u 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;

在三级继承的情况下,
dynamic\u 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;
}
#包括
#必须包含include//才能调用typeid()返回的typeinfo对象的任何成员函数
使用名称空间std;
C类数据库
{
公众:
虚拟空打印()
{
不能将指向CDerivedA(基类)的“指针”转换为“指向CDerivedB的指针”(派生类)。请注意,我指的不是声明的指针类型;问题是,指向的实际对象实际上是基类的一个实例,因此转换无法成功

dynamic_cast
在下行失败的情况下返回一个
null
-指针,这可能是分段冲突的原因(在抛出引用的情况下,它将抛出一个
bad_cast
异常)

请注意,
dynamic\u cast
需要(运行时类型信息)才能正常工作。出于性能原因,可以在编译器中关闭RTTI(因为启用RTTI会在运行时带来一些开销)。请仔细检查编译器中是否启用了RTTI

编辑:关于您最后的评论-

下行广播的基础知识 不能向下转换基类的实例。可以向下转换声明为“指向基类的指针”的指针,该指针实际上指向派生类的实例。可以使用向下转换的示例如下:

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. 
  } 

} 

我希望这有帮助

非常感谢您的更正。

指向CDerivedA(基类)的“指针”不能转换为“指向CDerivedB的指针”(派生类)。请注意,我指的不是声明的指针类型;问题是指向的实际对象实际上是基类的实例,因此无法成功

dynamic_cast
在下行失败的情况下返回一个
null
-指针,这可能是分段冲突的原因(在抛出引用的情况下,它将抛出一个
bad_cast
异常)

请注意,
dynamic\u cast
需要(运行时类型信息)才能正常工作。出于性能原因,可以在编译器中关闭RTTI(因为启用RTTI会在运行时带来一些开销)。请仔细检查编译器中是否启用了RTTI

编辑:关于您最后的评论-

下行广播的基础知识 不能向下转换基类的实例。可以向下转换声明为“指向基类的指针”的指针,该指针实际上指向派生类的实例。可以使用向下转换的示例如下:

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. 
  } 

} 

我希望这有帮助


非常感谢您的更正。

详细信息或没有发生。关于如何不在So上编写问题的完美示例显示您的代码,显示编译器错误消息…查看您的代码,我会说它工作正常,并且返回的
NULL
与它应该的完全一致。您是否打算编写
新CDerivedB
?@molbdnilo:不,我只是想了解对象的类型是否与基本指针(ptrB)相同要点必须是CDerivedB。它看起来更像是我们经常做的向下投射,但实际上有不同的事情。你认为在这个例子中向下投射是不可能的吗?详细信息还是没有发生。如何不在SOS上写问题的完美例子显示你的代码,显示编译器错误消息…看看你的代码,我会假设它正常工作,它返回的
NULL
与它应该返回的完全一样。您是否打算编写
new CDerivedB
?@molbdnilo:不,我只是想知道对象的类型是否与基指针(ptrB)相同要点必须是CDerivedB。它看起来更像是我们经常做的向下投射,但实际上有不同的事情。你认为在这个例子中向下投射是不可能的吗?@TadeuszKopec:当然,非常感谢!我更新了我的答案。看起来更像是我故意向下投射基类的一个实例。我阅读了最近在cplusplus中。这些语句真的让我困惑。对于动态\u转换(source\u pointer),source\u pointer的类型怎么可能是destination*的基类,大多数情况非常简单:检索源指针的RTTI信息,并获取类型destination*的RTTI信息。然后库例程确定源指针的类型是destination*类型还是destination*基类非常感谢你的好例子。所谓向下投射只是指从基类指向派生类的指针,实际上,指针指向的对象是“向上投射”的,因此它可以保证一个完整的对象。你同意吗?@yao:“向下投射只是指从基类指向派生类的指针”-确切地说,实际上,指针指向的对象没有任何改变。@:UpUp是从指针到派生类型到指针到基类的转换。这不需要显式的C++,例如:<代码>派生*P派生=新派生()。;Base*pBase=pDerived;
注意,指向的对象仍然是
派生的
的实例,它没有降级为
Base
。升级总是安全的,而且总是成功的。@TadeuszKopec:当然,非常感谢!我已经更新了我的答案。看起来更像是我故意降级了基类的一个实例。当我阅读想想最近的cplusplus。这些语句真的让我困惑。对于动态的\u转换(source\u pointer),source\u指针的类型怎么可能是destination*的基类,大多数情况都非常简单:检索源指针的RTTI信息,获取类型destination*的RTTI信息