0

我在尝试将一个类向下转换为另一个类以访问该类的特定方法时遇到了几个问题。这是我目前的课程计划:

游戏对象类:

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_;
}

小地精类:

#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";
    }
}
...
}

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

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

4

3 回答 3

4

您在您正在存储的评论之一中提到std::vector<GameObject>。不幸的是,这将导致您的GameObject对象被切片。可以在这里找到一个很好的描述:什么是对象切片?

“切片”是将派生类的对象分配给基类的实例,从而丢失部分信息 - 其中一些信息被“切片”掉了。

为了解决这个问题,你需要存储一个指针向量。如果您使用的是 C++11,您可以在这里进行一些选择。您可以存储:

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

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

于 2013-04-28T22:47:45.403 回答
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);

顺便说一句,我会改用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";
}
于 2013-04-28T21:27:26.457 回答
-1

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

于 2013-04-28T22:06:45.410 回答