4

我有一个类Enemy,我想成为所有敌人类型的基类,也是纯抽象类。此时,它的所有成员和方法都应该由派生类共享。特别是,有loadTexture使用静态成员的方法texture

    class Enemy
    {
        int hp;
        int damage;
        //
        // all other fields
        //
        static TextureClass* texture; //needs to be static because every instance
                                      //of enemy uses the same texture
    public:
        static void loadTexture()
        {
            CreateTextureFromFile("somefilepath",&texture); //needs to be static
          // because textures are loaded before any instance is crated
        }
        void draw()
        {
            DrawToScreen(&texture, ...many data members passed here...);
        }
    };

    TextureClass* Enemy::texture = nullptr;

现在,如果我想进行Enemy抽象并创建不同的敌人类型,显而易见的选择是继承。所以我创建:

class EnemyA : Enemy
{
    static TextureClass* texture;
};

class EnemyB : Enemy
{
    static TextureClass* texture;
};

但是现在,我如何为每个加载纹理?loadTexture我显然不能在 base 中使用定义。因此,除了编写 X 次相同的方法(其中 X 是敌人类型的数量)之外,唯一的选择是loadTexture从基础中移除并创建一个全局函数,对吗?同样适用draw,我需要为每个派生重新定义它,即使它看起来完全一样......

TL;DR无论敌人类型如何loadTexturedraw他们都拥有完全相同的身体,但他们使用的静态场各不相同。有没有办法定义类似统一方法的东西,当在派生类中调用时会使用派生的字段,而不是基类?

谢谢你的任何答案。

4

2 回答 2

7

正如 BЈовић 所提到的,如果你想使用继承让 loadTexture() 和 draw() 方法为你的类引用正确的纹理,答案可能在于使用CRTP来实现你的 Enemy 类,如下所示:

template<typename TDerivedEnemy>
class Enemy
{
    int hp;
    int damage;
    //
    // all other fields
    //
    static TextureClass* texture; //needs to be static because every instance
                                  //of enemy uses the same texture
public:
    static void loadTexture()
    {
        CreateTextureFromFile("somefilepath",&texture); //needs to be static
      // because textures are loaded before any instance is crated
    }
    void draw()
    {
        DrawToScreen(&texture, ...many data members passed here...);
    }
};

完成后,您可以声明具体的敌人类,如下所示:

class EnemyA : public Enemy<EnemyA>
{
public:
    typedef Enemy<EnemyA> tBase;
    ...
};

class EnemyB : public Enemy<EnemyB>
{
public:
    typedef Enemy<EnemyB> tBase;
    ...
};

然后,在您的实现文件中,您还需要为 EnemyA 和 EnemyB 定义静态变量:

TextureClass* EnemyA::tBase::texture = nullptr;
TextureClass* EnemyB::tBase::texture = nullptr;

“Curiously Recurring Template Pattern”这个名字来源于 EnemyA 和 EnemyB 继承自一个模板类,它们已经是参数模板,因此是递归的。

编辑:正如评论中所讨论的,这种方法导致 EnemyA 和 EnemyB 没有共同的基类,这使得无法以统一的方式引用它们,即你不能声明例如 a

std::vector< EnemyA* OR EnemyB* ??? > enemies;

因为根本没有一个通用的基类。为了解决这个问题,您可以声明一个通用的抽象基类,如下所示:

class EnemyBase {
public:
    virtual void draw() = 0;
}

然后让你的模板实现继承它:

template<typename TDerivedEnemy>
class Enemy : public EnemyBase
{
    ...
};

它允许您这样做:

std::vector<EnemyBase*> enemies;

//fill the enemies vector
...

for (auto enemy : enemies)
{
    enemy->draw();
}
于 2013-10-12T12:05:29.697 回答
1

有几种方法:

  1. 使 EnemyX 成为具有静态纹理变量的模板。您甚至可以为此使用CRTP
  2. 将纹理对象传递给敌人对象(某种IOC) - 传递给构造函数或方法。在这种情况下,纹理不是静态的,而是指向纹理对象(指针或引用)
于 2013-10-12T10:39:41.657 回答