简体   繁体   English

使用静态方法/字段继承c ++

[英]Inheritance with static methods/fields c++

I have a class of Enemy that i want to be the base class for all enemy types and also pure abstract one. 我有一类Enemy ,我想成为所有敌人类型的基类,也是纯粹的抽象类。 At this point, all of its members and methods should be shared by the derived classes. 此时,派生类应共享其所有成员和方法。 Especially, there is the method loadTexture that uses the static member texture . 特别是,有一个方法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;

Now, if i would like to make the Enemy abstract and create different enemy types, the obvious choice would be inheritance. 现在,如果我想让Enemy抽象并创造出不同的敌人类型,那么明显的选择就是继承。 So i create: 所以我创建:

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

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

But now, how do i load the texture for each of those? 但是现在,我如何为每个加载纹理? I can't use loadTexture defined in base obviously. 我显然不能使用base中定义的loadTexture So the only choice besides writing the same method X times (where X is the number of enemy types) is to remove loadTexture from base and create a global function, right? 所以除了编写相同的方法X次(其中X是敌人类型的数量)之外,唯一的选择是从base移除loadTexture并创建一个全局函数,对吗? Same goes for draw , i would need to redefine it for every derived, even though it would look exactly the same... 同样适用于draw ,我需要为每个派生重新定义它,即使它看起来完全一样......

TL;DR The loadTexture and draw have exact same body regardless of the enemy type, but they use the static field that is different in each one. TL; DR无论敌人类型如何, loadTexturedraw都具有完全相同的主体,但它们使用每个不同的静态字段。 Is there a way to define something like an uniform method, that when called in derived class would use the field from the derived, not the base? 有没有办法定义类似于统一方法的东西,在派生类中调用时会使用派生的字段而不是基数字段?

Thank You for any answers. 谢谢你的任何答案。

As mentioned by BЈовић, if you want to use inheritance to have the loadTexture() and draw() methods reference the right Texture for your class, the answer probably lies in using CRTP to implement your Enemy class, like follows: 正如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...);
    }
};

Once that is done, you can declare your concrete enemy classes like follows: 完成后,您可以声明具体的敌人类,如下所示:

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

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

then, in your implementation file, you also need to define the static variables for both EnemyA and EnemyB: 然后,在您的实现文件中,您还需要为EnemyA和EnemyB定义静态变量:

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

The name "Curiously Recurring Template Pattern" comes from the fact that EnemyA and EnemyB inherit from a template class where they already are parameter templates, hence recursion. 名称“Curiously Recurring Template Pattern”来自EnemyA和EnemyB继承自模板类的事实,其中模板类已经是参数模板,因此递归。

Edit: as discussed in the comment, this approach leads to EnemyA and EnemyB having no common base class, which makes it impossible to refer to them in a uniform way, ie you can't declare for instance a 编辑:正如评论中所讨论的,这种方法导致EnemyA和EnemyB没有共同的基类,这使得无法以统一的方式引用它们,即你不能声明例如

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

because there simply isn't a common base class. 因为根本就没有共同的基类。 To get around this, you can declare a common abstract base class like follows: 要解决这个问题,您可以声明一个公共抽象基类,如下所示:

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

then make your template implementation inherit from it: 然后让你的模板实现从它继承:

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

Which allows you to do this: 这允许你这样做:

std::vector<EnemyBase*> enemies;

//fill the enemies vector
...

for (auto enemy : enemies)
{
    enemy->draw();
}

There are several ways : 有几种方法:

  1. make EnemyX a template, that has a static texture variable. 使EnemyX成为一个模板,它具有静态纹理变量。 You can even use CRTP for this 您甚至可以使用CRTP
  2. pass the texture object into the enemy objects (some kind of IOC ) - either to constructor or a method. 将纹理对象传递给敌人对象(某种IOC ) - 无论是构造函数还是方法。 In this case, the texture would not be static, but it would point to the texture object (pointer or a reference) 在这种情况下,纹理不会是静态的,但它会指向纹理对象(指针或引用)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM