オブジェクトの生成/消滅時に呼び出されるコンストラクタとデストラクタ。これらをマスターすれば、確実かつ適切な初期化/終了処理が記述できる。
本記事は、(株)技術評論社が発行する書籍『新プログラミング環境 C#がわかる+使える』から許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。
C#はクラスを記述する能力があり、クラスからインスタンスを生成することができる。インスタンスの生成/消滅の際には、何かのコードを実行させたい場合がある。特に、インスタンスの初期化を行うためのコードを書く必要は頻繁に発生する。本章では、それらの機能を実現する「コンストラクタ」と「デストラクタ」について解説する。
クラス内に変数などがある場合、インスタンスを生成してから変数を利用するまでの間に、適切な値を初期値として設定したい場合がある。また、入出力機器を扱うクラスなら、入出力ハンドルを初期化したいと思うこともあるだろう。そのような場合に対応するために、C#にはコンストラクタという機能がある。コンストラクタは、インスタンスが生成された瞬間に実行されるメソッドの一種である。このメソッドにインスタンス生成時に実行させたいコードを書いておけば、自動的に生成時に呼び出され、実行される。
最も簡単なコンストラクタの例をList 11-1として示す。
1: using System;
2:
3: namespace Sample001
4: {
5: class Class2
6: {
7: public Class2()
8: {
9: Console.WriteLine("public Class2()");
10: }
11: }
12: class Class3
13: {
14: public Class3( int x, int y )
15: {
16: Console.WriteLine("public Class3({0},{1})",x,y);
17: }
18: }
19: class Class1
20: {
21: [STAThread]
22: static void Main(string[] args)
23: {
24: Class2 t1 = new Class2();
25: Class3 t2 = new Class3( 1, 2 );
26: }
27: }
28: }
7〜10行目がClass2クラスのコンストラクタである。7行目を見て分かるとおり、コンストラクタの名前は、クラス名と一致させなければならない。また、コンストラクタは暗黙のうちに実行されるため、戻り値は存在しない。そのため、戻り値のデータ型は書かない。事実上voidに相当するが、voidとは書かない。
このコンストラクタを明示的に呼び出すコードはソース上のどこにもないが、24行目でClass2クラスのインスタンスがnewによって生成された時点で、自動的に呼び出されている。
コンストラクタに戻り値はない。しかし、引数を付けることはできる。引数のあるコンストラクタの事例が14〜17行目のClass3クラスのコンストラクタである。ここでは、整数型のxとyという引数を持っている。このコンストラクタを呼び出す場合は、25行目のように、newでクラス名を記述した後に引数のリストを記述する。newがコンストラクタを必ず呼び出すのは明らかなので、newに書いた引数は確実にコンストラクタに届く。
これを実行するとFig.11-1のようになる。明示的には呼び出されていないコンストラクタが呼び出されている様子が分かると思う。
C#には、1つのクラスに引数の異なる同名のメソッドを扱う機能がある。これを「オーバーロード」という。コンストラクタもオーバーロード可能なので、引数の異なる複数のコンストラクタを1つのクラスに持たせることができる。List 11-2はその例である。
1: using System;
2:
3: namespace Sample002
4: {
5: class Class2
6: {
7: public Class2()
8: {
9: Console.WriteLine("public Class2() called");
10: }
11: public Class2( int x )
12: {
13: Console.WriteLine("public Class2( int x ) called");
14: }
15: public Class2( string s )
16: {
17: Console.WriteLine("public Class2( string s ) called");
18: }
19: }
20: class Class1
21: {
22: [STAThread]
23: static void Main(string[] args)
24: {
25: Console.WriteLine("new Class2();");
26: Class2 t1 = new Class2();
27: Console.WriteLine("new Class2( 1 );");
28: Class2 t2 = new Class2( 1 );
29: Console.WriteLine("new Class2(( \"Hello!\" );");
30: Class2 t3 = new Class2( "Hello!" );
31: }
32: }
33: }
7〜10行目は引数のないコンストラクタ、11〜14行目は引数に1つの整数を取るコンストラクタ、15〜18行目は引数に1つの文字列を取るコンストラクタである。
これを実行した結果がFig.11-2である。
実行結果を見れば分かるとおり、1回のnewで実行されるコンストラクタは1つきりである。コンストラクタが複数存在していても、実行されるのは、その中の1つだけである。
複数のコンストラクタがあっても、実行されるのは1つきりである。しかし、共通の初期化などがあった場合、このような仕様は不便である。1個のコンストラクタの処理を行うとき、別のコンストラクタも呼べれば、ずっとプログラムがすっきりする。そこで、明示的に同じクラス内にある別のコンストラクタを呼び出す構文がC#には用意されている。具体的には、List 11-3のサンプル・ソースのように記述する。
1: using System;
2:
3: namespace Sample003
4: {
5: class Class2
6: {
7: public Class2()
8: {
9: Console.WriteLine("public Class2() called");
10: }
11: public Class2( int x ) : this()
12: {
13: Console.WriteLine("public Class2( int x ) called");
14: }
15: public Class2( string s ) : this(1)
16: {
17: Console.WriteLine("public Class2( string s ) called");
18: }
19: }
20: class Class1
21: {
22: [STAThread]
23: static void Main(string[] args)
24: {
25: Console.WriteLine("new Class2();");
26: Class2 t1 = new Class2();
27: Console.WriteLine("new Class2( 1 );");
28: Class2 t2 = new Class2( 1 );
29: Console.WriteLine("new Class2( \"Hello!\" );");
30: Class2 t3 = new Class2( "Hello!" );
31: }
32: }
33: }
まず11行目に注目していただきたい。11行目には、前のサンプルにない「: this()」という文字列が付加されている。これは、このコンストラクタの実行に先立って、同じクラス内で、引数なしのコンストラクタを実行せよ、という意味を持つ。つまり、7〜10行目のコンストラクタが、11〜14行目のコンストラクタの実行に先立って実行するように指示している。
「: this()」の括弧内には引数を記述することができる。15行目が引数を記述した例である。引数に1という数字を記述しているが、これはint型である。int型を1個引数に取るコンストラクタといえば、11〜14行目のコンストラクタであるから、このコンストラクタが呼び出されることになる。
これを実行した結果はFig.11-3のようになる。
ここで注意していただきたいのは、コンストラクタが実行される順番である。例えば、「new Class2( "Hello!" );」で実行されるコンストラクタは「public Class2( string s ) : this(1)」である。しかし、このコンストラクタを実行する前に「: this(1)」によって、「public Class2( int x ) : this()」が実行される。しかし、これを実行する前に、「: this()」の効能により、「public Class2()」が実行される。その結果、直接指定したコンストラクタの実行は最後にまわされる。
Copyright© Digital Advantage Corp. All Rights Reserved.