まずはクラスの基本的な例を示して書いていきたいと思います。
//ヘッダーファイル========
//CCharacter.h
//====================
class CCharacter
{
public:
//フィールド=================
int m_iHp;
//========================
CCharacter(); //コンストラクタ
~CCharacter(); //デストラクタ
//メソッド===================
void damage(int val);
//========================
};
//cppファイル==========
//CCharacter.cpp
//===================
#include "CCharacter.h"
CCharacter::CCharacter()
{
m_iHp = 100;
}
CCharacter::~CCharacter()
{
}
void CCharacter::damage(int val)
{
m_iHp -= val;
if(m_iHp < 0) m_iHp = 0;
}
製作をしていく上で、ソースを分けることが基本になると思いますので、今回はヘッダーファイルと、cppファイルに分けてみました。
ヘッダーファイルには、定義、そして、cppファイルには、その中身が書いてあります。
1年次で習うC言語であった、プロトタイプ宣言、とその実装と全く同じです。ソースが変わっただけですね。
ではまずヘッダーファイルから、見て行きましょう。
プログラムの書き方
class CCharacter
{
・・・
Characterクラスなのに、なぜか頭文字にCが付いている…。
そして、変数にもなんか付いてますね。
これは
ハンガリアン記法といいます。
どういうものかと言いますと、
型名、変数名を見ただけで何か分かるようにしてあるのですね。
わざわざこういう書き方をしなくても、全然動くのですが、
就職に向けてプログラムの書き方というものについて、知ってもらいたいと思いあえて書かせていただきました。
なぜこういうことをするのかと言うと、またもや
多人数製作のためなのです。
プログラムを書く上で、ルールというものを決めていると、他人が自分のソースを見たときに、一体それが何なのかをすぐに理解出来ますよね。
(勿論
会社では、しっかりと決められています)
例えば先ほどの Character 。
『 C 』 がなければ、それが変数名なのか、構造体なのか、何なのか分かりません。
でも、
CCharacter と書いてあると、一発でクラスと分かるんです。
あくまで、これはハンガリアン記法という既存のルールなので、別にこれに縛られる必要はありません。
しっかりと、自分の決めたルールに則って、分かりやすいように書けば問題ないのです。
実際、会社によって違ったりもします。
かといって、逸脱したルールは駄目ですが(笑
Characterはクラス名なので、前にclassの『C』を付けました。
また、m_iHp という変数は、メンバ変数ということで、『 m_ 』 (メンバ変数に関しては第1回を参照)
『 i 』 は 整数型 という意味です。
int 、char の場合は、よく『 n 』 も使われます。
ちなみに float は『 f 』、 double は『 d 』 などがあります。
後、グローバル変数は『 g_ 』、ローカル変数は『 l_ 』になります。
詳しくはググってください。
私も全部知っているわけではないので・・・。
こういう書き方をしていると、
就職にも有利になるので、是非マスターしてください。
というか、明日から始めてみよう!
後、
変数名は必ず英語にしましょう。
C言語、C++言語は世界共通言語です。
是非、電子辞書は片手に!
メンバ関数
では次に、C言語の構造体との最大の違い、メンバ関数について説明したいと思います。
class CCharacter
{
・・・
//メソッド===================
void damage(int val);
//========================
・・・
};
クラスの中に、『フィールド』、『メソッド』 とありますよね。
メンバ変数のことを『フィールド』と言います。
そして、
メンバ関数を『メソッド』と言います。
別にメンバ変数、メンバ関数と書いてもよかったのですが、知っていて欲しい言葉であったため、あえてそうしました。
メンバ関数とは、その名の通り、
クラス内に存在する関数のことです。
クラスに関数をつけることによって、意味を持たせることができるのです。(なんか言い方が分かりにくいかも・・・)
このキャラクターは void damage(int val) という関数によって、『 ダメージを受けるもの 』 という意味がつくのですね。
使い方は変数のときと同じです。
例えば、このキャラクターがダメージを受けたとします。
main()
{
CCharacter player;
plyer.m_iHp -= 10; //プレイヤーがダメージを受けた
if(player.m_iHp < 0) player.m_iHp = 0;
plyer.m_iHp -= 20; //プレイヤーがダメージを受けた
if(player.m_iHp < 0) player.m_iHp = 0;
}
とかくより、
main()
{
CCharacter player;
player.damage(10); // プレイヤーがダメージを受けた
player.damage(20); // プレイヤーがダメージを受けた
}
のほうが分かりやすくありませんか?
また、ダメージを2回受けたときなど、あきらか下のほうがいいですよね。(
同じプログラムを2回書くなどもっての外です!)
これ以外にも、回復など、メンバ変数を増やせば、攻撃や、防御などの関数も加えていけます。
いわゆる、このCCharacterクラス一つで、キャラクターの制御がすべて出来てしまうのです!!
第1回で、オブシェクト思考について説明いたしましたが、このようにして
キャラクターという一つのオブジェクトを作成していくのがオブジェクト指向であり、C++言語の醍醐味なのです。
最後にメンバ関数の実装の仕方ですが
戻り値 クラス名 :: 関数名( 引数 ){}
となります。
『コンストラクタ』 と 『デストラクタ』
もうひとつ、C言語の構造体と、決定的に違うものがあります。
それが、『コンストラクタ』 と 『デストラクタ』です。
class CCharacter
{
・・・
CCharacter(); //コンストラクタ
~CCharacter(); //デストラクタ
・・・
};
クラス内に、戻り値のない、クラス名と同じ関数っぽいものがありますよね。
それが、コンストラクタとデストラクタとなります。
最初に結論を言ってしまうと、
『コンストラクタ』 はインスタンス(実体)が生成されたときに自動で呼び出される関数で、
『デストラクタ』 はインスタンスが破棄されたときに自動で呼び出される関数です。
いわゆる、
コンストラクタは初期化を勝手に行ってくれるのですね!
すごく便利なものだと思いませんか?
コンストラクタの書き方は クラス名(引数)
デストラクタの書き方は ~クラス名() (~はチルダ)
となっています。
main()
{
CCharacter player; //インスタンス(実体)の生成
printf("HP = %d¥n", player.m_iHP);
} //←ココでデストラクタが通ります
これを実行すると、HP = 100 と表示されるはずです。
ちゃんと初期化されていますね。
playerはローカル変数なので、main関数が終わるところで、インスタンスは破棄されるのでデストラクタが通ります。
現状ではデストラクタの使い道が分からないとおもいますが、メンバ変数でポインタ宣言をしていたり、特殊な処理をする場合は結構使ったりします。
今は、そういうのがあって、どういうときに通るのかを理解していただいてくれたら結構です。
最後に、
初期化子について話しておきたいと思います。
皆さん、下のプログラムの違いがわかりますか?
int a = 100;
と、
int a;
a = 100;
です。
前者は、宣言と同時に初期化していますね。
後者は、宣言だけして、 a = 100; は代入をしています。
『初期化と代入は違うもの』 このことを理解してください。
前者は、作られたと同時に値が入っていますが、後者は、一度作られた後に、値の代入が行われているわけなんです。
後者では一段階処理が増えているわけですね。
このように
無駄な処理のことを『オーバーヘッド』と言います。
C++のコンストラクタでも、実は同じことが起こっています。
CCharacter::CCharacter()
{
m_iHp = 100;
}
実は、これは後者と同じ状態になっています。
コンストラクタは、そのクラスのインスタンスが生成されたと同時に通るのですが、コンストラクタの中身
(中かっこで囲われた部分)自体はインスタンスが生成された後に通ることになっています。
どういうことかというと、m_iHpが宣言された後に、m_iHp = 100; が通ってしまっているのですね。
これを防ぐ方法があります。
CCharacter::CCharacter() : m_iHp(100)
{
}
コンスラクタの後ろに
: 変数名(初期値)
つけるだけで改善できます。これで、前者と同じ動きになります。
もし、初期化したいものがたくさんあったならば、 コロンを付けて繋げていったら大丈夫です。
CCharacter::CCharacter() : m_iHp(100), m_iMp(50)
{
}
のような感じですね。
以上のことを、初期化子といい、初期化子が並んでいることを、
初期化リストといいます。
アクセス指定子
やっとここまできました。
これが本当の最後です。
最後はアクセス指定子についてです。
class CCharacter
{
public:
・・・
};
おそらく気になってた人もいると思いますが、public: という変なものがついてますよね。
これは、アクセス指定子といい、これより下に書いてあるものが、
どこからアクセスできるかを設定するためにあります。
このクラスにはpublicしか存在しませんが、ほかに private があります。 (他にも protected がありますが、こちらは『継承』というものをしたときに説明します)
public はクラス外からでも、アクセスが出来るということを意味し、
privateはクラス内でしか、アクセス出来なくなります。
一つ、クラスを作って例を示したいとおもいます。
class CStudent
{
private:
char m_sName[256]; //名前
public:
int m_iId; //ID番号
CStudent(char* name, int id) : m_sName(name), m_iId(id){} //コンストラクタ
~CStudent(){} //デストラクタ
void printName(){ printf("Name = %s¥n" ,m_sName); }
};
main()
{
CStudent anonymous(中原, 26); //初期化
printf("ID = %d¥n!, anonymous.m_iId); //①
printf("Name = %s¥n"anonymous.m_sName); //②
anonymous.printName(); //③
}
ちょっと、応用がはいっちゃってますが、
コンストラクタには、引数が指定でき、初期値を入れることが出来ます。
また、
クラス定義内でも、中身を書くことも出来ます。
これは、コンストラクタだけでなく、関数も出来ますので覚えておいてください。
短い関数などは、この方が便利だったりします。
①は ID = 26 と表示されます。
が、②は
m_sName がprivate であるために、アクセス不可となり、表示することができません。
それどころか、コンパイルもエラーとなってしまいます。
③は、m_sName にアクセスできないものの、クラス内で表示しているために、しっかりと Name = 中原 と表示されます。
どうでしょう?
例で分かりましたか?
この例で、私の名前の匿名性がアップしてるのが分かりますか?
ある生徒のID番号は分かっても、名前を知ることは出来ないですよね。
実際、ゲーム製作の場合でも、同じことが言えるのです。
他の人に自分の作ったクラスを渡した場合、そのクラスを使う人がメンバ関数を扱う際に
private に設定しておけば、中身をいじれないし見ることも出来ません。
いわゆる、
そのメンバ関数自体の存在を教えなくてすむわけなんですね。
例では匿名性でしたが、
実際では、『メンバ変数として必要だけど、使う人は知らなくてよい変数、関数』 に private を使用します。
使う人にとって情報は少しでも少ないほうがいいですから。
このことを
『カプセル化』 といいます。
この言葉は是非覚えておいてください。
お疲れ様でした。
以上で、今日講座は終了です。
結局、構造体とクラスの何が違うのかというと、それは、
意味合いだけなのです。
メンバ関数が必要ないものであるならば、構造体にしてやってください。
それでも、ちゃんと、コンストラクタ、デストラクタを作ってやれば通ります。
ほんと、それだけなんですよね。
長かったですねぇ。
書くのに3時間以上かけてしまいました。
皆さんは大丈夫だったでしょうか?
ほんとは2回くらいに分けたほうがいいかもと思ったのですが、これがほんとに基本なので一気にやってしまいました。
飽きずに見てくださった方がいらっしゃいましたら感激で涙がでそうです。
次回は、ポインタを使って、C++のメモリ確保をコンストラクタ、デストラクタを交えて、問題形式で行いたいと思います。
では、皆さんありがとうございました。
中原でした。
PR
COMMENT
無題
ファイト!
無題
早速直しておきます。
無題
第三回も期待してますー
一応補足です。
アクセス指定子を指定していない状態だと
デフォルトでは
structはpublic
classはprivate
となっています。
無題
書くの忘れてました。有難うございます。
今、色々カテゴリを増やしたり、中身を細分化したりと、C++入門用のサイトをしっかり作っていこうと思っています。
その時に色々つけたしていきますので、私が書き忘れていることや、付け足したらいいのでは?と思ったことは、どんどんコメントお願いします。
頑張って、GESブログを盛り上げて行きましょう!
おっ
参考資料がいくつかありますがお役に立てればかいますよ。
GESブログももっと盛り上がってほしいですね。
参考資料
C++リファレンス
デザインパターン
グラフィックス
etc…