将指针从基类型转换为子类型

时间:2012-10-22 14:19:09

标签: c++ polymorphism

我正在为我的一个项目构建一个简单的游戏设计。我有以下课程:

class Character
{
public: 
   virtual void Display();
   virtual void SetParameters( char* param, ... );
};

class NonPlayableCharacter : public Character
{

public:
   virtual void Display();
   virtual void SetParameters( char* paaram, ... );
   int GetNPCState();
}

然后我有一堆派生于Character或NonPlayableCharacter的类。我这样定义:

std::vector<Character*> _allChar;

我的问题是,在任何给定的时间,我都想对矢量的一个元素执行一些操作。因此,从向量中获取元素我无法直接调用方法GetNPCState(),因为向量中的元素是Character *类型。所以这样做:

_allChar[0]->GetNPCState();

不起作用。所以我尝试使用着名的dynamic_cast:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
test->GetNPCState();

最后一次尝试的问题是GetNPCState()崩溃,因为对象为空,我知道(通过调试)_allChar [0]不为空。

7 个答案:

答案 0 :(得分:6)

C ++(4)中有几种类型的强制类型,其中2种是有兴趣的:

  • static_cast假设您知道自己在做什么
  • dynamic_cast在运行时检查您是否已经猜到&#34;右

注意:简化,因为dynamic_cast也允许包含虚拟基础的交叉投射和强制转换。

dynamic_cast有3个版本,实际上,取决于目标的性质:

  • 如果目标是引用(即dynamic_cast<T&>(u)),那么如果检查失败dynamic_cast则会引发std::bad_cast异常
  • 如果目标是指针(即dynamic_cast<T*>(p)),那么如果检查失败dynamic_cast则返回空指针
  • 最后,作为一种特殊情况,如果目标是void*,则dynamic_cast会返回完整对象的地址

在这种情况下,您可以:

  • dynamic_cast<NonPlayableCharacter*>(_allChar[0])->getNPCState()切换到 dynamic_cast<NonPlayableCharacter&>(*_allChar[0]).getNPCState(),让异常传播
  • 测试演员(NonPlayableCharacter* test此处)的非无效性
  • 的结果

答案 1 :(得分:5)

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);

您应该检查test是否为NULL。即使_allChar[0]不是NULL,dynamic_cast如果指向的对象不是NULL,也可以返回NonPlayableCharacter

所以正确的版本是:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if (test)
{
   test->GetNPCState();
}

答案 2 :(得分:3)

如果无法投射,

dynamic_cast会返回NULL。检查_allChar[0]内的内容。您可以使getType()之类的函数返回对象预定义的类型ID,然后使用static_cast

if (_allChar[0]->getType() == TYPE_NO_PLAYER) {
    static_cast<NonPlayableCharacter*>(_allChar[0])->getNpcState();
}

答案 3 :(得分:2)

您必须测试dynamic_cast是否成功。它在失败时返回空指针:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if (test) test->GetNCPState();

问题可能是你的第一个元素没有指向NonPlayableCharacter对象。

答案 4 :(得分:2)

dynamic_cast在其参数未指向NULL时返回NonPlayableCharacter(因此数组中的第一个元素可能指向Character的其他子类) - 所以你需要在演员表之后检查NULL。但是,使用dynamic_cast可能表示存在设计问题。也许您应该在Character上使用虚拟方法,例如PerformMainActionInGameLoop()并在不同的子类中被适当地覆盖?

答案 5 :(得分:2)

要从基指针获取子指针,您必须使用dynamic_cast。其行为如下:

  • 如果指针指向分配有Child*的{​​{1}},则new Child会返回dynamic_cast<Child*>
  • 如果指针指向其他内容,则Child*会返回dynamic_cast

您的问题是,您未使用NULL分配,或者您的对象属于不同类型。

答案 6 :(得分:2)

使用dynamic_cast可能有更好的OO解决方案,但使用此强制转换的全部意义在于,如果转换失败,它将返回NULL指针。

因此在调用GetNPCState();

之前检查NULL
NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if( test != NULL )
{   
     test->GetNPCState(); 
}