クラスまみれのゲームプログラミング入門

4:クラス、子供を作る

 クラスは子どもを作ること(C++では「継承」と呼ばれています)ができます。親クラス(C++では「基本クラス」と呼びます)を持つ子クラス(C++では「派生クラス」と呼びます)は以下のように記述することで作成します。

class [子クラスの名前] : [親クラスの名前]
{
    [子クラス独自の変数・関数]
};

 子クラスのメリットは、親の遺伝子(情報)を受け継ぎながらも、子どもだけの新しい遺伝子を付加することができる点にあります。

 例えば、3種類の敵がいるとして、1つめには「耐久性・得点」の情報が、2つめには「耐久性・得点・移動パターン」の情報が、3つめには「耐久性・得点・向いている方向」の情報が含まれている必要があるとします。それぞれの敵のデータを管理するためにCEnemy1、CEnemy2、CEnemy3のクラスをそれぞれ作成したとき、もし子どもを作ることができないとしたら、プログラムコードは

class.cpp
class CEnemy1
{
private:
	int hardness;	//耐久性
	int score;		//得点
public:
	CEnemy1;		//コンストラクタ
	void SetHardness(int val);
	void SetScore(int val);
};

CEnemy1::CEnemy1()
{
	score = 0;
	hardness = 0;
}

void CEnemy1::SetHardness(int val)
{
	hardness = val;
}

void CEnemy1::SetScore(int val)
{
	score = val;
}

class CEnemy2
{
private:
	int hardness;	//耐久性
	int score;		//得点
	int x, y;		//現在の位置
public:
	CEnemy2();		//コンストラクタ
	void SetHardness(int val);
	void SetScore(int val);
	void Move();
};

CEnemy2::CEnemy2()
{
	score = 0;
	hardness = 0;
	x = 200;
	y = 0;
}

void CEnemy2::SetHardness(int val)
{
	hardness = val;
}

void CEnemy2::SetScore(int val)
{
	score = val;
}

void CEnemy2::Move()
{
	y += 10;
}

class CEnemy3
{
private:
	int hardness;		//耐久性
	int score;			//得点
	float direction;	//向いている方向
public:
	CEnemy3();		//コンストラクタ
	void SetHardness(int val);
	void SetScore(int val);
	void SetDirection(float val);
};

CEnemy3::CEnemy3()
{
	score = 0;
	hardness = 0;
	direction = 0.0f;
}

void CEnemy3::SetHardness(int val)
{
	hardness = val;
}

void CEnemy3::SetScore(int val)
{
	score = val;
}

void CEnemy3::SetDirection(float val)
{
	direction = val;
}

このように、「得点」と「耐久性」のプログラム内容は全く同じであるにもかかわらず、長ったらしくなってしまうだけではなく、得点に関する設定を1つ変えようとしても、CEnemy1からCEnemy3までに含まれている得点情報をひとつひとつ修正していかなくてはならず、大変手間がかかります。

 しかし、「子作り」の概念があれば、「得点」と「耐久性」のDNAを持つ「CEnemy」クラスをあらかじめ作成しておくことで、子クラスのCEnemy1~CEnemy3の記述は簡単になります。

class2.cpp
class CEnemy
{
private:
	int hardness;	//耐久性
	int score;		//得点
public:
	CEnemy();		//コンストラクタ
	void SetHardness(int val);
	void SetScore(int val);
};

CEnemy::CEnemy()
{
	score = 0;
	hardness = 0;
}

void CEnemy::SetHardness(int val)
{
	hardness = val;
}

void CEnemy::SetScore(int val)
{
	score = val;
}

class CEnemy1 : CEnemy
{
	// 今回の例では特別追加する要素は無し
	CEnemy1();
};

CEnemy1::CEnemy1()
{
	// 親クラスのコンストラクタ関数を入れておかないと
	// hardnessとscoreの値が初期化されないことに注意
	CEnemy();
}

class CEnemy2 : CEnemy
{
private:
	int x, y;		//現在の位置
public:
	CEnemy2();
	void Move();
};

CEnemy2::CEnemy2()
{
	CEnemy();

	x = 200;
	y = 0;
}

void CEnemy2::Move()
{
	y += 10;
}

class CEnemy3 : CEnemy
{
private:
	float direction;	//向いている方向
public:
	CEnemy3();		//コンストラクタ
	void SetDirection(float val);
};

CEnemy3::CEnemy3()
{
	CEnemy();

	direction = 0.0f;
}

void CEnemy3::SetDirection(float val)
{
	direction = val;
}

 しかしながら、このプログラム例のように

test.cpp
void main()
{
	CEnemy2 e2;
	e2.SetScore(100);
}

CEnemy2オブジェクトに対して得点を設定しようとしてみても、コンパイルエラーとなってしまいます。その理由と対策法は次回にて解説。