コンストラクタとデストラクタ
このインスタンスを生成するときに実は新しい機能が用意されています。
それはコンストラクタとデストラクタという機能です。
機能と言っても関数で実現されているのですが。
partychara というクラスに同じなまえの
partychara(); という関数を定義すると、それは自動的にコンストラクタとなります。
~partychara(); という、あたまに~(チルダ)をつけた関数を定義すると、それはデストラクタになります。
コンストラクタ、は日本語では「建設者」、デストラクタは「破壊者」ですね。
コンストラクタはクラスのインスタンスを生成するときに呼び出されます。
デストラクタはクラスが消滅するときに呼び出されます。
ほかの関数と違うのは、戻り値を持たないことその他ですが、その他については問題になる事はすくないと思いますので省略します。
興味のあるひとはヘルプを見てください。
では、コンストラクタを作ってどう働くのか、試してみましょう。
コンストラクタの例 ----------------------
#include <iostream.h>
class partychara{
partychara();
}
partychara::partychara()
{
cout << "コンストラクタが呼ばれた";
}
void main()
{
partychara p1();
}
今までの説明では、partychara クラスのインスタンスの生成には
partychara p1;
でよかったはずです。
しかし、コンストラクタを自分で作るとこれではエラーになってしまいます。
partychara p1();
というようにp1 に () をつけなければなりません。
通常はコンストラクタはメンバ変数の初期化に使います、というかその必要がなければコンストラクタを作る意味がありませんね。
以下のようになります。
自分で作ったコンストラクタの例----------------
#include <iostream.h>
class partychara{
char *name;
int age;
int hp;
int trib;
public:
partychara(char *nameis, int ageis, int hpis, int tribis);
};
partychara::partychara(char *nameis, int ageis, int hpis, int tribis)
{
name = nameis;
age = ageis;
hp = hpis;
trib = tribis;
cout << "コンストラクタでごじます";
}
void main()
{
partychara p1("sukenosuke",1,2,3);
}
main() にある
partychara p1("sukenosuke",1,2,3);
の部分ですね。
partychara p1 のオブジェクトを作るときにこうすればメンバ変数にすべて値を入れることができます。
ポインタなどが初期化されないまま使われるといったミスがなくなるわけです。
partychara p1("ichiro",1,2,3);
partychara p2("jiro",1,2,3);
partychara p3("saburo",1,2,3);
とすると3つのオブジェクトが出来ます。
配列にしてコンストラクタを使う場合は
partychara myparty[3]={
partychara ("ichiro",1,2,3),
partychara ("jiro",1,2,3),
partychara ("saburo",1,2,3),
};
のように記述します。
コンストラクタには多重定義というものがあります。
上の例では、すべての変数に値をいれるようなコンストラクタにしました。
しかし、名前だけ入れたい場合はどうしましょうか。
ついでにほかの変数もいれればいいではないですか。
そうですね。でもメンバ変数が100個あって、必要なのが3個だけだとします。
名前と年齢だけ、とかですね。
そういう時のために多重定義を使います。
これは、コンストラクタとして、
どのメンバ変数も初期化しないコンストラクタ
partychara::partychara()
名前だけを初期化するコンストラクタ
partychara::partychara(char *nameis)
年齢だけを初期化するコンストラクタ
partychara::partychara(int ageis)
名前と年齢とヒットポイントだけを初期化するコンストラクタ
partychara::partychara(char *nameis, int ageis, int hpis)
名前、年齢、ヒットポイント、種族 のすべて初期化するコンストラクタ
partychara::partychara(char *nameis, int ageis, int hpis, int tribis)
と、5種類のコンストラクタを作ってしまうのです。
乱暴に見えますね。
こうすると、
partychara p1(15);
と書くと、 int型の引数一つ持っているのは 年齢だけを初期化するコンストラクタなのでそれが呼ばれます。
partychara p2("sanda",99,6000);
これに相当するのは名前、年齢、ヒットポイントのコンストラクタです。
このように同じなまえで動作が違うコンストラクタを作のが多重定義です。
もちろん、同じ引数を使うものは定義できません。
しかし、多重定義はよほど上手に使わないと混乱の元になりそうな予感がしますね。
最後にクラス内の static に付いて説明しておきましょう。
int a; と違って static int a; はたくさんオブジェクトと作っても一つしかありません。
class partychara{
static int ninzu; // 宣言
int a;
name *char;
int hp;
};
int partychara::znum = 0; // 定義
とした場合に、int a, name, hp は出来たオブジェクトの数だけ存在します。
5人いたら、ヒットポイントと名前も5個ないといけません。
当たり前ですね。
しかし、どのオブジェクトからでも ninzu を読み出すと、それは一つしかありません。
つまりパソコン上のメモリに、名前とヒットポイントは5個あるけど、ninzu は一つしかない、ということですね。
場合によってははかなり便利です。
パーティのメンバーは動的に作られたりなくなったりするばあい、作られると ninzu+1
なくなるとninzu -1 としておくと、現在作られているインスタンスがいくつあるか数えることができます。
コンストラクタによってたくさんクラスを作った場合にどのようになるか実際にやってみましょう。
static メンバ変数の例 ----------------------------------------------
#include <iostream.h>
class partychara{
private:
static int znum; // 宣言する
char *name;
int age;
int hp;
int trib;
public:
int getznum(){ return znum;};
partychara(char *nameis, int ageis, int hpis, int tribis);
};
partychara::partychara(char *nameis, int ageis, int hpis, int tribis)
{
name = nameis;
age = ageis;
hp = hpis;
trib = tribis;
cout << "コンストラクタでごじます" << endl;
znum +=1;
cout << getznum() << endl;
}
int partychara::znum = 1234; // 定義する
void main()
{
partychara p1("sukenosuke",1,2,3);
partychara myparty[3]={
partychara ("ichiro",1,2,3),
partychara ("jiro",1,2,3),
partychara ("saburo",1,2,3),
};
cout << p1.getznum() << endl;
}
クラスの定義のなかで
dtatic int znum = 0;
とつい書きたくなりますが、これだとエラーになってしまいます。
コンストラクタの中で
int znum = 0;
というのはどうでしょうか。
これでは新しいオブジェクトが出来るたびに定義しなおされてしまうのでstatic にする意味がなくなります。
上のコードを実行した結果は以下の通り。
E:\myproject\test\ddd>
コンストラクタでごじます
1235
コンストラクタでごじます
1236
コンストラクタでごじます
1237
コンストラクタでごじます
1238
1238
Press any key to continue
1234で初期化された(定義された)znum がコンストラクタが呼び出されるたびに1づつ増やして表示、となっています。
オブジェクトは新しく作られてもstatic znum は値を保持していますね。