2013-04-28 44 views
0

我有几个问题试图向下转换到另一个类访问该类的具体方法。这是我目前的课程方案:向下转换dynamic_cast和多态类不工作

游戏对象类:

class GameObject 
{ 
... 
} 

敌对阶级:

#include "../GameObject.h" 

class Enemy : public GameObject 
{ 
Enemy(Type type); 
virtual ~Enemy(); 
virtual int receiveDamage(int attack_points); 
virtual void levelUp() = 0; 
... 
protected: 
char *name_; 
int level_; 
int health_; 
int max_health_; 
int attack_; 
int armor_; 
} 

SmallGoblin类:

#include "../Enemy.h" 

class SmallGoblin : public Enemy 
{ 
public: 
SmallGoblin(); 
~SmallGoblin(); 

void levelUp(); 
} 

在我的代码,我尝试做这个和每次抛出std :: bad_cast异常。

class Player : GameObject 
{ 
... 
virtual void attack(GameObject &enemy) 
{ 
try 
    { 
     Enemy &e = dynamic_cast<Enemy&>(enemy); 
     e.receiveDamage(attack_points_); 
    } 
    catch(const std::bad_cast& e) 
    { 
     std::cerr << e.what() << '\n'; 
     std::cerr << "This object is not of type Enemy\n"; 
    } 
} 
... 
} 

(敌人是一个GameObject对象的引用,但是我知道它实际上是一个SmallGoblin对象)。

在其他部分我的代码我有anoother类(门),它扩展了GameObject类和向下转换工作(但是,我必须使用static_cast而不是dynamic_cast,我不知道为什么)。

+0

你能提供一个SSCCE吗? – chris 2013-04-28 21:21:10

+0

我会用我真实的代码更新这个问题。 – Puyover 2013-04-28 21:21:49

+0

如果你不得不使用'static_cast',你可能会得到未定义的行为。 – 2013-04-28 21:23:05

回答

4

您在其中一条评论中提到您正在存储std::vector<GameObject>。不幸的是,这会导致您的GameObject对象成为sliced。一个伟大的描述可以在这里找到:What is object slicing?

“切片”是你分配一个派生类对象的基类的实例,从而失去的部分信息 - 有一些是“切片”远。

要解决此问题,您需要存储指针向量。如果你使用C++ 11,你在这里有一些选择。你可以存储:

std::vector<GameObject*> badGameObjects; 
std::vector<std::unique_ptr<GameObject>> uGameObjects; 
std::vector<std::shared_ptr<GameObject>> sGameObjects; 

所有这些选项将确保切片不会发生,因为矢量只是存储指针。存储裸指针是最不理想的选择,因为您必须自己管理内存,并且可能成为内存泄漏的来源。使用unique_ptrshared_ptr将取决于您需要如何使用这些对象。

+0

谢谢你正式确认答案。我会改变它,如我之前所说:P – Puyover 2013-04-28 22:55:41

+0

它现在正在工作。真的很有趣,事情如何在内部工作... – Puyover 2013-04-29 02:22:24

2

如果dynamic_cast失败,那么enemy实际上并不是有效的Enemy实例,因此仔细检查如何管理该引用。

class GameObject 
{ 
public: 
    virtual ~GameObject(){} 
}; 

enum Type {goblin}; 

class Enemy : public GameObject 
{ 
public: 
    Enemy(Type type) : type_(type) {} 
    virtual ~Enemy() {} 
    virtual int receiveDamage(int attack_points) {} 
    virtual void levelUp() = 0; 
protected: 
    Type type_; 
    //... 
}; 

class SmallGoblin : public Enemy 
{ 
public: 
    SmallGoblin() : Enemy(goblin) {} 
    ~SmallGoblin() {} 

    void levelUp() {} 
}; 

class Player : GameObject 
{ 
public: 
    int attack_points_; 

    virtual void attack(GameObject &enemy) 
    { 
     try 
     { 
      Enemy &e = dynamic_cast<Enemy&>(enemy); 
      e.receiveDamage(attack_points_); 
     } 
     catch(const std::bad_cast& e) 
     { 
      std::cerr << e.what() << '\n'; 
      std::cerr << "This object is not of type Enemy\n"; 
     } 
    } 
}; 

:当我尝试它

下工作正常,我。

Player p; 
SmallGoblin goblin; 
p.attack(goblin); 

BTW,我会用dynamic_cast用指针来代替,以避免使用异常的不必要的开销:

virtual void attack(GameObject &enemy) 
{ 
    Enemy *e = dynamic_cast<Enemy*>(&enemy); 
    if (e) 
     e->receiveDamage(attack_points_); 
    else 
     std::cerr << "This object is not of type Enemy\n"; 
} 
+0

每次我得到一个GameObject是否通过对它的引用都没关系?因为我的所有GameObject都存储在std :: vector中,并且在问题的情况下,引用通过GameObject&传递给3函数。我不知道在这个过程中类型是否会“丢失”...... – Puyover 2013-04-28 22:04:46

+1

@Puyover我怀疑切片是你问题的根源。如果你使用std :: vector 那么你正在遭受切片:http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – Steve 2013-04-28 22:11:21

+0

@Steve谢谢你的说法。任何关于如何解决它的想法? :/ – Puyover 2013-04-28 22:35:50

-1

dynamic_cast不应该被用于向下转换,我敢肯定static_cast做的工作。相反,dynamic_cast用于“上传”。

+1

但是上传是一个隐含的操作。没有必要使用像dynamic_cast这样的显式投射来实现它... – Puyover 2013-04-28 22:10:02

+0

http://en.wikipedia.org/wiki/Dynamic_cast 我很确定这不是隐含在这个例子中。 – lucas92 2013-04-28 22:11:25

+0

推导是公开的时候隐式发生。 – jweyrich 2013-04-28 23:12:14