以前、この辺でも書いた補足であるが、インスタンスの生成について、少々追補しなければならない。
- なんてこった??newしなくても使えてしまう
動的に、宣言したクラスを、インスタンス化せずに使うとどうなるのだろう?何と、使えてしまうのである。この辺,非常に分かりにくい部分ではあるが、継承によるユーザ拡張を目的としたクラスライブラリを定義する場合には、絶対必要な技術になるのである。不思議な事に、インスタンス化する時、動的に確保するメモリの無い、つまり、クラスが変数部分を持たない(private:で変数を宣言していない)場合は、機能的にも全然問題は発生しないのである。しかしながら、deleteを実行しても、デストラクタは呼ばれていない。
→サンプルのtest016_1参照
逆に、変数が有ると、コンパイルではエラーにはならないが、実行時にエラーになってしまうのだ。多分、必要なメモリを、変なメモリエリアにメモリを確保していて、deleteを実施すると、違うエリアを消そうとするのでは無いだろうか?
→サンプルのtest016_2参照…但し、実行するとエラーになるので注意!
とにかく、正式には、newして、生成してから使い、deleteで消去しておけば、問題は出ないのだから、その様にすべきなのだが、止むを得ない場合は、この辺りの事情を、キッチリ押さえて考えなければならないのだ。
- これって何とかならないのか?
個人で管理する場合は、こんな事は考えないと思うが、クラスの本質上、『クラスを造って、みんなに使って貰う』若しくは、『クラス単位で、機能を開発し、後で組み合わせて使う』と言った事象に必ず出会うのである。では、自分の造ったクラスを、ユーザに使って貰う場合、この様な事象をどの様に回避すべきなのか?悩んだあげく、自分なりに、一つの方策を考えたので、ここに追記しておく。
クラスの外部制御変数(勝手に付けた…)を使うのである。
具体的には、クラスの外部に、グローバル変数として、そのクラスの生成状況をコントロールするフラグを用意しておき、このフラグの状態に応じて、不正な呼び出しを防ぐのである。例えば、プログラムの最初に、このフラグをFALSEにセットし、コンストラクタが呼ばれた時点でTRUEにセットし、逆に、デストラクタが呼ばれた時点で、
FALSEにセットする。という仕組みを入れておけば、このフラグがFALSEの
場合は、呼び出しをさせない(スキップする)処理を入れれば良いのである。(もし、グローバルのフラグを使うのが不安という場合は、別のクラスを作成し、静的に生成して、それを使う方法も有りだな)
→簡単なサンプルを、test016_3として用意した。
- 継承したクラスのコンストラクタに引数が有る場合の処理
以前にも実験した通り、「ClassA」という基本クラスを、「ClassB」という派生クラスが継承する場合、ClassAのコンストラクタClassA()が、引数を持たない場合は、何も小細工しなくても、ClassBのコンストラクタを呼び出せば、ClassAのコンストラクタが、自動で呼び出されたのである。さて、では、ClassAのコンストラクタが引数を持っていた場合は、どの様に処理(記述)すれば良いのだろうか?ここで、その記述方法を追補しておく。記述方法は、ClassBのコンストラクタを、メンバ関数として記述する際、そこに続けて、: ClassA()の様に記述してしまえば良いのである。説明するより、以下の具体例と、サンプル(test016_4)を見て貰った方が分かりやすいだろう。
class ClassA
{
……
int ValueA ;
public:
ClassA(int) ;
……
} ;
class ClassB : public ClassA
{
……
int ValueB ;
public:
ClassB(int,int) ;
……
} ;
|
の様な場合、
ClassA::ClassA(int a)
{
ValueA=a ;
}
……
ClassB:ClassB(int a,int b) : ClassA(a)
{
ValueB=b ;
}
|
の様に記述すれば良いのである。
サンプル016のソース
|