C++ 使用静态方法/字段c++;

C++ 使用静态方法/字段c++;,c++,inheritance,static-methods,static-members,C++,Inheritance,Static Methods,Static Members,我有一个敌人的类,我想成为所有敌人类型的基类,也是纯粹的抽象类。此时,它的所有成员和方法都应该由派生类共享。特别是,有一种方法loadTexture,它使用静态成员texture class Enemy { int hp; int damage; // // all other fields // static TextureClass* texture; //needs to be

我有一个
敌人的类
,我想成为所有敌人类型的基类,也是纯粹的抽象类。此时,它的所有成员和方法都应该由派生类共享。特别是,有一种方法
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;
现在,如果我想将
敌人
抽象化并创建不同的敌人类型,显然的选择是继承。因此,我创建:

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

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

TL;无论敌方类型如何,DR
loadTexture
draw
都有完全相同的身体,但它们使用的静态场在每一个方面都不同。有没有一种方法可以定义类似于统一方法的东西,当在派生类中调用时,它将使用派生类中的字段,而不是基类中的字段


谢谢您的回答。

有几种方法:

  • 使EnemyX成为具有静态纹理变量的模板。你甚至可以用这个
  • 将纹理对象传递给敌人对象(某种类型)-构造函数或方法。在这种情况下,纹理将不是静态的,但它将指向纹理对象(指针或引用)

  • 正如B所述,如果您想使用继承让loadTexture()和draw()方法为您的类引用正确的纹理,答案可能在于使用实现您的敌人类,如下所示:

    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;
        ...
    };
    
    class EnemyBase {
    public:
        virtual void draw() = 0;
    }
    
    “奇怪地重复出现的模板模式”的名称来自这样一个事实:EnemyA和EnemyB继承自一个模板类,它们已经是参数模板,因此是递归

    编辑:正如评论中所讨论的,这种方法导致EnemyA和EnemyB没有公共基类,这使得不可能以统一的方式引用它们,也就是说,您不能声明实例a

    std::vector< EnemyA* OR EnemyB* ??? > enemies;
    
    然后使模板实现从中继承:

    template<typename TDerivedEnemy>
    class Enemy : public EnemyBase
    {
        ...
    };
    
    模板
    阶级敌人:公共敌人基地
    {
    ...
    };
    
    这允许您执行以下操作:

    std::vector<EnemyBase*> enemies;
    
    //fill the enemies vector
    ...
    
    for (auto enemy : enemies)
    {
        enemy->draw();
    }
    
    std::向量敌人;
    //填充敌人向量
    ...
    用于(自动敌人:敌人)
    {
    敌人->抽签();
    }
    
    创建一个虚拟方法,
    TextureClass*getTexture()
    ,所有子类都实现该方法来检索其纹理指针,并使用常用方法来获取纹理指针。如果必须使用静态方法,则可以使用。否则,将首选非静态虚拟方法。@mah by'common method'您是指'global function'?@tomi.lee.jones否,我的意思是
    loadTexture
    draw
    ,您说过这两种方法对于所有子类都是相同的(使它们成为通用的)。因此,现在调用'objectOfEnemyA.draw()'将使用子类中的纹理,而不是基类中的纹理,即使我没有在“enemyA”中定义它?另外,如何处理静态“加载纹理”?我不能调用“EnemyA::loadTexture()”,对吗?创建一个获取纹理地址并加载它的全局函数不是更好吗?您不需要在EnemyA类中定义纹理,因为它已经在EnemyA的基类:敌人中定义了。大多数编译器应该允许您直接调用EnemyA::loadTexture(…),但在一些较旧的编译器上,您可能需要调用EnemyA::tBase::loadTexture(…)。CRTP的一个要点是,它允许你通过模板实例化过程为你创建静态元素,从而有效地“继承静态内容”。CRTP使得创建例如单例基模板类非常有用,我想我现在明白了:以这种方式派生的类不会共享相同的纹理,因为它们不是从“敌人”派生的,而是从“敌人”派生的,是吗?所以事实上,他们好像不是来自同一个“敌人”?是的,就是这样。请注意,这引发了一个问题:您不能通过多态性引用敌人,因为它们没有派生自的公共基类。您可以通过定义这样一个基类并使敌人的类模板继承它来绕过它。在您的情况下,这个基类可能会声明virtualvoiddraw()=0;作为一种抽象的方法。然后你可以做一些类似于std::vector仇敌。。。;对于(自动敌人:敌人)敌人->绘制();编辑答案以添加此选项。
    std::vector<EnemyBase*> enemies;
    
    //fill the enemies vector
    ...
    
    for (auto enemy : enemies)
    {
        enemy->draw();
    }