tom*_*nes 4 c++ inheritance static-methods static-members
我有一类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;
Run Code Online (Sandbox Code Playgroud)
现在,如果我想制作Enemy抽象并创建不同的敌人类型,显而易见的选择将是继承.所以我创建:
class EnemyA : Enemy
{
static TextureClass* texture;
};
class EnemyB : Enemy
{
static TextureClass* texture;
};
Run Code Online (Sandbox Code Playgroud)
但是现在,我如何为每个加载纹理?我loadTexture显然无法在基础中定义.所以除了写X次相同的方法(其中X是敌人类型的数量)之外,唯一的选择是loadTexture从基数中移除并创建一个全局函数,对吗?同样的draw,我需要为每个派生重新定义它,即使它看起来完全一样......
TL;博士loadTexture和draw具有完全相同的机身敌我不分类型,但他们使用的静态字段是在每一个不同的.有没有办法定义类似于统一方法的东西,在派生类中调用时会使用派生的字段,而不是基数字段?
谢谢你的任何答案.
正如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...);
}
};
Run Code Online (Sandbox Code Playgroud)
完成后,您可以声明具体的敌人类,如下所示:
class EnemyA : public Enemy<EnemyA>
{
public:
typedef Enemy<EnemyA> tBase;
...
};
class EnemyB : public Enemy<EnemyB>
{
public:
typedef Enemy<EnemyB> tBase;
...
};
Run Code Online (Sandbox Code Playgroud)
然后,在您的实现文件中,您还需要为EnemyA和EnemyB定义静态变量:
TextureClass* EnemyA::tBase::texture = nullptr;
TextureClass* EnemyB::tBase::texture = nullptr;
Run Code Online (Sandbox Code Playgroud)
名称"Curiously Recurring Template Pattern"来自EnemyA和EnemyB继承自模板类的事实,其中模板类已经是参数模板,因此递归.
编辑:正如评论中所讨论的,这种方法导致EnemyA和EnemyB没有共同的基类,这使得无法以统一的方式引用它们,即你不能声明例如
std::vector< EnemyA* OR EnemyB* ??? > enemies;
Run Code Online (Sandbox Code Playgroud)
因为根本就没有共同的基类.要解决这个问题,您可以声明一个公共抽象基类,如下所示:
class EnemyBase {
public:
virtual void draw() = 0;
}
Run Code Online (Sandbox Code Playgroud)
然后让你的模板实现从它继承:
template<typename TDerivedEnemy>
class Enemy : public EnemyBase
{
...
};
Run Code Online (Sandbox Code Playgroud)
这允许你这样做:
std::vector<EnemyBase*> enemies;
//fill the enemies vector
...
for (auto enemy : enemies)
{
enemy->draw();
}
Run Code Online (Sandbox Code Playgroud)