Downcasting与dynamic_cast和多态类不工作

Downcasting with dynamic_cast and polymorphic classes not working

本文关键字:多态 工作 cast dynamic Downcasting      更新时间:2023-10-16

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

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

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

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

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

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

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

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

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

如果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 Enemyn";
        }
    }
};

.

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 Enemyn";
}

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