[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
最後ということで、ちょっと復習から。
C++言語には3本柱という3つの大事な要素があります。
第1に『カプセル化』
これは、そのクラスを使用する人に、その人にとって知る必要のないメソッドやフィールドを扱えないように、もしくは隠しわからないようにさせることです。
一番簡単な方法は講座でも説明したように、メンバメソッドや、フィールドをprivateや、protectedにすることですよね。
でも実は、まだまだそれでは完全なカプセル化とは言えません。
ほんとは様々な技術やアルゴリズムを用いてカプセル化していくのですが…。
ぶっちゃけ完全なカプセル化というものはプロでも難しいものです。
今はそこまで気にせず、常に『カプセル化』ということを頭に留めながら、この講座で習ったことだけをやっていただければ結構です。
第2に『継承』
コレはあえてもう一度述べるまでもありませんね。
でも、それだけではちょっと寂しいので、『コンポジション』というちょっと新しいことをついでにやってみましょう。
『コンポジション』とは、「構成(すること)、組み立て(ること)」、いわゆる構成物ということです。
とりあえず簡単な例を。
//剣クラス
class CWepon
{
//略
};
//キャラクタークラス
class CChara
{
protected:
CWepon m_Sword;
//略
};
武器クラスが、ありキャラクタークラスがあり、ただキャラクタークラスが武器クラスを持っている。
コレを『コンポジション』といいます。
キャラクタークラスは、武器クラス(など)から構成されている。いわゆる構成物であるのです。
英語の意味そのまんまですよね。
しかも誰もがやったことのある書き方だと思います。
実はこんなたいそうな名前が付いてたんですね。
また、なんでこの継承のところで引っ張り出してきたかと言うと、実は
class CChara : public CWepon
{
//略
};
このように書いても、CCharaクラスでは違いがないのがわかりますか?
継承だろうと、コンポジションだろうと、結局CCharaクラスでCWeponクラスの中身を見ることが出来、アクセスが出来ることは変わりません。
でも、この書き方に違和感を持って欲しいのです。
あくまで、武器はキャラクターが持っているのであって、武器がキャラクターになるわけではありませんよね?
常に、これは『継承』なのか『コンポジション』なのかというのを気にしてください。
C++言語ではこのような意味合いがとても大切になってきます。
勿論意味合いだけではありませんよ。
今回のは武器とキャラということで割合簡単に分かるものですが、システム関係などとなってくると、結構悩んだりします。
その場合、しっかりと『継承』、『コンポジション』が出来ていれば、カプセル化もしやすくなりますし、クラスの構成もとても綺麗に出来、見やすく分かりやすいプログラムが出来上がります。
是非悩んでください!
なんかコレで終わりのような感じですが…。
まだ今日の目玉も始まっていないのですね。
どうも脱線が長くなってすみません。
気を取り直して、第三の『ポリモフィズム』にいってみましょう。
『ポリモフィズム』は、多態性、多相性、多様性と言われています。
が、こんなこと言われても、さっぱり分からないですよね。
私は始めて聞いたとき意味不明でした。
なぜ、プログラムをしているのに、そんな生物学的な言葉が出てくるのか…。
ぶっちゃけ、私は無視しました。
そんなもの使わなくてもC++は出来る!と勝手に思い込んでましたね。
確かに使わなくても出来るのですが、それは1年生の最後や、2年生の最初までと思っていてください。
本格的にゲームを作り始めたらコレがなければ、ソースは汚くなるわ、見にくくなるわでいいことありません。
ポリモフィズムを分かりやすく噛み砕いて言うと、
クラスの各要素(メンバメソッドや、メンバフィールドなど)について、それらが複数の型に属することを許すということです。
いやぁ、これでも分かりにくそうだ。
例をあげますと
class CBaseChara
{
public:
void Move();
};
class CPlayer : public CBaseChara
{
//略
};
main()
{
CBaseChara* p = new CPlayer;
p->Move();
};
となります。
CPlayerが、違う型であるCBaseCharaであることを許していますよね。
そうです。第8回でやった内容が実はポリモフィズムなんです。
では、なぜここまで延ばしたかというと、第7回にやりました『仮想関数』と重ねることで、ものすごい効果を出すことが出来るのです。
では早速例を
//キャラクターのベースとなるクラス
class CBaseChara
{
public:
virtual void Move() = 0;
};
//プレイヤークラス
class CPlayer : public CBaseChara
{
public:
void Move()
{
printf("プレイヤーが動いた\n");
}
};
//味方クラス
class CFriend : public CBaseChara
{
public:
void Move()
{
printf("味方が動いた\n");
}
};
//敵クラス
class CEnemy : public CBaseChara
{
public:
void Move()
{
printf("敵が動いた\n");
}
};
キャラクターのベースとなるクラスがあり、Moveという仮想関数を持っています。
そしてそれを継承して、プレイヤー、味方、敵クラスをMove関数を実装して作っています。
早速使ってみましょう。
CBaseChara* g_pCharaList[3];
main()
{
g_pCharaList[0] = new CPlayer;
g_pCharaList[1] = new CFriend;
g_pCharaList[2] = new CEnemy;
for(int i = 0; i < 3; i++){
g_pCharaList[i]->Move();
}
delete g_pCharaList[0];
delete g_pCharaList[1];
delete g_pCharaList[2];
}
本当はCBaseCharaのリストを作るべきなのですが、見た目がややこしくなりそうなのであえて配列にしています。
実際のゲームでは、そのリストをCCharacterManagerなど、キャラクターを管理するクラスとして作ってあげてください。
プログラムの流れは、グローバル変数であるCBaseChara*の配列に、プレイヤークラス、味方クラス、敵クラスの実体を入れています。
これはポリモフィズムで可能ですよね。
で、その次に、CBaseChara*のMove()関数を呼び出しています。
これで、何が呼び出されるのかというと…?
プレイヤーが動いた
味方が動いた
敵が動いた
と表示されるのが分かりますか。
第7回の仮想関数で勉強しましたよね。
そうなんです!
CBaseChara*のリスト作るだけで、それから派生したクラス全てを管理することが出来るのです。
勿論、キャストしない限り、基底クラスに存在するメソッド、フィールドしか扱うことは出来ませんが…。
キャストするために、基底クラスにIDでも付けてみるのもいいかもしれませんね。
それでも、この機能は素晴らしいと思いませんか?
全てが同じ型で管理できる為、キャラクターの管理がしやすいうえに、当たり判定などもわざわざ全てのクラスについて考えなくても大丈夫です。
このやり方は、もうC++言語では当たり前のように使われているテクニックです。
キャラクター管理だけでなく、システム関係でも使えるのでガンガン使ってやってください。
勿論、基底クラスにリストクラスを作ってあげて、継承させてあげれば、ものすごく使いやすくなります。
講座は以上です。
またもや大分長くなってしまったような…。
C++言語はゲーム業界では必須の言語です。
もちろん、そのテクニックも必要となってきます。
勿論私も全てを知っているわけではありませんし、まだまだ勉強中です。
それでも基本となるべきことを知っていなければ、業界の方と話していても話が進みません。
基本さえしっかりと身に付ければ、応用は後でいくらでも付いてきます。
今回の講座の内容は基本のことばかりですので、何度も言うようですが、絶対にモノのしてください。
中原でした。
COMMENT
No Title
No Title
勉強になりました。