次のクラスを検討してください。(ゲームからですが、大幅に単純化されています。)
戦闘.h:
class Combat {
public:
Combat();
Combat(int health, int offense, int defense);
virtual ~Combat();
int attack();
int defend();
int health() const;
void setHealth(int health);
private:
struct CombatImpl;
std::unique_ptr<CombatImpl> _impl;
};
戦闘.cc:
struct Combat::CombatImpl {
CombatImpl();
CombatImpl(int health, int offense, int defense);
~CombatImpl()=default;
int _health;
int _offense;
int _defense;
};
Combat::Combat(int health, int offense, int defense) :
_impl { new Combat::CombatImpl(health, offense, defense) } {
}
Combat::~Combat()=default;
int Combat::attack() {
int hits = 0;
for(int i = 0; i < _impl->_offense; i++ ) {
if (rand() % 6 == 5) {
hits++;
}
}
return hits;
}
int Combat::defend() {
int parries = 0;
for(int i = 0; i < _impl->_defense; i++ ) {
if (rand() % 6 == 5) {
parries++;
}
}
return parries;
}
int Combat::health() const {
return _impl->_health;
}
void Combat::setHealth(int health) {
_impl->_health += health;
}
Combat::CombatImpl::CombatImpl(int health, int offense, int defense) {
_health = health;
_offense = offense;
_defense = defense;
}
モンスター.h:
class Monster: public Combat {
public:
Monster(int health, int offense, int defense);
virtual ~Monster();
}
モンスター.cc:
Monster::Monster(int health, int offense, int defense)
: Combat(health, offense, defense) {}
Monster::~Monster()=default;
player.h:
class Player : public Combat {
public:
Player();
virtual ~Player();
private:
struct PlayerImpl;
static PlayerImpl _impl;
};
player.cc:
struct Player::PlayerImpl {
PlayerImpl()=default;
~PlayerImpl()=default;
} Player::_impl;
Player::Player() : Combat(17, 1, 1) {
}
Player::~Player()=default;
...そして最後に、それらを使用するテスト プログラム:
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <memory>
using namespace std;
#include "monster.h"
#include "player.h"
static Monster monster(3, 1, 1);
void fight() {
Player player;
int damage = monster.attack();
damage -= player.defend();
if ( damage > 0 ) {
player.setHealth(-damage);
}
if ( player.health() < 1 ) {
return;
}
damage = player.attack();
damage -= monster.defend();
if ( damage > 0 ) {
monster.setHealth(-damage);
}
if ( monster.health() < 1 ) {
return;
}
}
int main() {
Player player;
srand(time(NULL));
while (player.health() > 0 && monster.health() > 0) {
fight();
printf("player health = %d monster health = %d\n", player.health(),
monster.health());
}
}
このプログラムを実行すると、機能しないことがわかります。モンスターの体力は当然減少しますが、プレイヤーの体力は初期値のままです。それが起こっていると私が思う理由はこれです。Player には静的データしかありません (PlayerImpl _impl にカプセル化されています)。これは、コード内のさまざまな関数から呼び出すことができる 1 つのグローバル Player オブジェクトを持つことができるようにするためです。(モノステート パターン。) しかし、その基本クラスの Combat は動的です。つまり、Player プレーヤーを作成するたびに、何が起こっているのかということです。Fight() では、実際に Combat::_health がデフォルト値である新しい Combat を取得しています。プレイヤーが範囲外になると、_health への変更はすべて失われます。Monster では、Monster オブジェクトにも動的データがあるため、これは問題になりません。と言えるのが理想です。
class Player : public static Combat {
この特定の戦闘のみを静的にすることを意味しますが、それは構文エラーです。それを行う別の方法はありますか?それとも、私は自分自身を隅に追いやったのですか?