7

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

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] 不为空。

4

7 回答 7

6

C++ 中有几种类型的强制转换 (4),其中 2 种在这里感兴趣:

  • static_cast假设你知道你在做什么
  • dynamic_cast在运行时检查您是否“猜”对了

注意:简化,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此处)是否为非空值
于 2012-10-22T14:40:38.420 回答
5

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

你应该检查是否testNULL。即使_allChar[0]不是 NULL,dynamic_cast如果NULL它指向的对象不是NonPlayableCharacter.

所以正确的版本是:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if (test)
{
   test->GetNPCState();
}
于 2012-10-22T14:22:03.803 回答
3

dynamic_castNULL如果演员是不可能的,则返回。检查里面有什么_allChar[0]。您可以制作类似getType()where 返回对象预定义类型 id 的函数,然后使用static_cast

if (_allChar[0]->getType() == TYPE_NO_PLAYER) {
    static_cast<NonPlayableCharacter*>(_allChar[0])->getNpcState();
}
于 2012-10-22T14:21:44.607 回答
2

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

  • 如果指针指向一个已Child*分配的,new Childdynamic_cast<Child*>返回一个Child*
  • 如果指针指向别的东西,则dynamic_cast返回NULL

您的问题是您没有分配 with new,或者您的对象属于不同类型。

于 2012-10-22T14:23:06.437 回答
2

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

因此,在调用 GetNPCState() 之前检查 NULL;

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if( test != NULL )
{   
     test->GetNPCState(); 
}
于 2012-10-22T14:23:16.310 回答
2

你必须测试dynamic_cast成功。它在失败时返回一个空指针:

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

问题可能是您的第一个元素未指向NonPlayableCharacter对象。

于 2012-10-22T14:22:49.187 回答
2

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

于 2012-10-22T14:22:59.217 回答