2.2 生命体クラス(2) 1999.03.12(初版) 生命体のクラス設計の2つ目のバージョンは、継承を使うものです。継承とは既存の クラスからその属性と動作を受け継ぎ、その上に必要な機能を追加した新しいクラスを 作ることであり、ソフトウェア再利用の1つの形態です。 生命体の2つの状態、DYING(死んでいる)とLIVING(生きている)をクラスにするとどう なるでしょうか。これはちょっと奇妙にみえます。 状態ですから、(生命体の)DYING という状態。(生命体の)LIVING という状態です。 2つの共通部分は「生命体」です。 元になるクラスつまり基底クラスを life、 それを継承した派生クラスを dying およ びliving とします。基底クラス life は生命体から生死の状態を取り除いたものといえ ます。ですから、この基底クラスは生きているか死んでいるかが分からない抽象化された 実体のないものであることに注目しましょう(だから奇妙)。基底クラス lifeを次のよ うに書きます。
#include <iostream.h>
#include <time.h>
#include "glibw32.h"// グラフィックス・クラスライブラリ GLIBW32
const int N = 40; // 正方形の升目の数
enum state{ DYING, LIVING, STATES};
class life; // 前方宣言
typedef life* field[N][N];
// 生命体の抽象クラス
class life{
public:
virtual state getstate() const = 0; //状態の識別
virtual life* next(field) = 0; //次の状態
virtual void draw(GRAPH *) = 0; //描画関数
protected:
int row, col; // 位置
void count(field w, int sum[]) const;
}; |
// 生きている生命体のクラス
class living : public life{
public:
living(int r, int c) { row = r; col = c; } // コンストラクタ
state getstate() const { return LIVING; }
life* next(field);
void draw(GRAPH *g){
g->frectangle(row*10+3,col*10+3,row*10+7,col*10+7, WHITE);
}
};
// 死んでいる生命体のクラス
class dying : public life{
public:
dying(int r, int c) { row = r; col = c; } // コンストラクタ
state getstate() const { return DYING; }
life* next(field);
void draw(GRAPH *) { } // 何もしない
}; |
// 次の世代の状態を決定する
life* living::next(field w)
{
int sum[STATES];
count(w, sum);
if(sum[LIVING] == 2 || sum[LIVING] == 3)
return (new living(row, col));
else
return (new dying(row, col));
}
// 次の世代の状態を決定する
life* dying::next(field w)
{
int sum[STATES];
count(w, sum);
if(sum[LIVING] == 3)
return (new living(row, col));
else
return (new dying(row, col));
} |
// オブジェクトの生成
void init(field w)
{
for(int i = 0; i < N; ++i)
for(int j = 0; j < N; ++j)
w[i][j] = new dying(i,j);
}
// 生命体の初期設定
void create(field w, int i, int j)
{
// 生命体の生息パターン
delete(w[i][j+1]);
w[i][j+1] = new living(i,j+1);
delete(w[i-1][j]);
w[i-1][j] = new living(i-1,j);
delete(w[i][j]);
w[i][j] = new living(i,j);
delete(w[i+1][j]);
w[i+1][j] = new living(i+1,j);
delete(w[i+1][j-1]);
w[i+1][j-1] = new living(i+1,j-1);
}
// 世代交代
void update(field w)
{
field w_temp; // 一時的なポインタ
int i,j;
// 次の状態を一時的に記憶
for(i = 1; i < N-1; ++i)
for(j = 1; j < N-1; ++j)
w_temp[i][j] = w[i][j]->next(w);
for(i = 1; i < N-1; ++i)
for(j = 1; j < N-1; ++j){
delete(w[i][j]); // 古い状態を削除
w[i][j] = w_temp[i][j]; // 新しい状態をコピー
}
}
// オブジェクトの削除
void dele(field w)
{
for(int i = 0; i < N; ++i)
for(int j = 0; j < N; ++j)
delete (w[i][j]);
}
// 描画関数
void draw(GRAPH *g, field w)
{
g->cls(); // 画面消去
for(int i = 0; i < N; ++i)
for(int j = 0; j < N; ++j)
w[i][j]->draw(g);
Sleep(100); // 遅延関数(100ミリ秒間停止する)
} |
実行ファイルとソースファイルのダウンロードはこちらです、
| ライフゲーム (2)
実行ファイルとソース・ファイル Windows 95/ 98上で動作します。 |
life02.lzh (47KB) |
* このソフトウェアは、SYMANTEC. NORTON AntiVirus 5.0 でウィルス検査を 行っています。 * ファイルは吉崎栄泰氏による LHA (Copyright(c)1988-92 H.Yoshizaki)を 使って圧縮しています。
Copyright(c) 1999 Yamada,K