コンストラクタ
オブジェクトの初期化
ある程度プログラムになれた方であれば、初期化の重要さは十分に理解していると思います
C言語のモジュールを作ったとき、ある動作のための構造体を定義して
その構造体のための初期化と破棄専用関数を作った経験がある方も多いでしょう
オブジェクト指向では、この初期化の動作をコンストラクタという関数で行います
コンストラクタはオブジェクトの生成時に自動で呼び出される性質があり
オブジェクトが初期値として持つべき値などをここで設定することができます
コンストラクタ関数はクラスと同じ名前の関数です
コンストラクタを明示しなければ、コンストラクタは何もせずにオブジェクトを生成しますが
コンストラクタを定義している場合は、オブジェクト宣言時にそれを実行します
class class-name {
class-name();
};
class-name()がコンストラクタ関数になります
コンストラクタ関数の本体は、メンバ関数同様の方法で行います
ただし、コンストラクタには戻り値は存在しません
#include <iostream>
using namespace std;
class Kitty {
public:
Kitty();
} obj ;
Kitty::Kitty() {
cout << "Kitty on your lap\n";
}
int main() {
Kitty obj;
return 0;
}
このプログラムでは、コンストラクタが呼び出されると「Kitty on your lap」と表示します
注目していただきたいのは、グローバルオブジェクト obj とmain()関数内のローカルオブジェクト obj です
コンストラクタは、グローバル、ローカル問わず、オブジェクト生成時に発生しますが
グローバルとローカルでは、発生するタイミングが異なります
グローバルオブジェクトの場合は、プログラムの実行時にコンストラクタが呼び出されますが
ローカルオブジェクトの場合は宣言部に到達したときにコンストラクタが呼び出されます
コンストラクタ関数も、定義できる本体部分は関数と変わりません
つまり、通常の関数と同じようにあらゆる処理が可能ですが
オブジェクトの発生時に常に呼び出されるため、初期化に必要な処理のみにするのが好ましいですね
コンストラクタ関数も引数を受け取ることができます
この機能によって、より柔軟で汎用的なオブジェクトの初期化を行うことができます
通常の実用的なシステムプログラムでは、コンストラクタで初期化する値を渡し
その値を元に適切なオブジェクトを生成するというような方法が一般的です
#include <iostream>
using namespace std;
class Kitty {
public:
char *str;
Kitty(char *);
};
Kitty::Kitty(char *ch) {
str = ch;
}
int main() {
Kitty obj("Kitty on your lap");
cout << obj.str;
return 0;
}
このプログラムでは、コンストラクタに文字列を渡します
コンストラクタは渡された文字列をメンバ変数 str に代入します
オブジェクトの破棄
サンプルプログラムのような小規模なプログラムでは実感できませんが
大規模なシステム開発になると、オブジェクトの破棄には非常に気を使います
オブジェクトが確保しているヒープ領域の解放や
他のオブジェクトと共有しているアドレスなど、多くの問題があります
これらの扱いや解放を人間に依存させると、非常にバグやリークの多いプログラムになりかねません
そこで、オブジェクトの破棄もコンストラクタ同様に自動化することで
つまらないバグやメモリリークをできるだけ避けることができます
コンストラクタの逆の処理を担当するものがデストラクタ関数です
デストラクタ関数はオブジェクトの消滅時に自動的に呼び出される関数です
コンストラクタの名前の前にチルダ( ~ ) をつけるとデストラクタ関数になります
class class-name {
~class-name();
};
オブジェクトが破壊されるタイミングは、スコープから外れたときです
デストラクタ関数も、コンストラクタ関数と同じく戻り値はありません
さらにデストラクタ関数は、仮引数も受け取らない(渡せない)という特徴があります
#include <iostream>
using namespace std;
class Kitty {
public:
~Kitty();
};
Kitty::~Kitty() {
cout << "Kitty on your lap\n";
}
void createKitty() {
Kitty obj;
}
int main() {
createKitty();
createKitty();
return 0;
}
関数 createKitty() はKittyオブジェクトを内部で生成します
しかし、関数が終了するとともにオブジェクトが破棄されるためデストラクタが呼び出されます
2度 main() 関数内で createKitty() 関数を呼び出しているので
2度デストラクタ関数が呼び出されるのを確認してください