使用dynamic_cast和多态类无效的向下转换

时间:2013-04-28 21:19:53

标签: c++

我在尝试将一个类转换为另一个类来访问该类的特定方法时遇到了一些问题。这是我目前的课程方案:

GameObject类:

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对象。)

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

3 个答案:

答案 0 :(得分:4)

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

  

&#34;切&#34;您将派生类的对象分配给基类的实例,从而丢失部分信息 - 其中一些是&#34;切片&#34;程。

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

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

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

答案 1 :(得分: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";
}

答案 2 :(得分:-1)

dynamic_cast不应该用于向下转换,我很确定static_cast可以胜任这项工作。 dynamic_cast用于“向上转换”。