継承におけるコンストラクタとデストラクタ
コンストラクタの実行順序
派生クラスは基本クラスのメンバを引き継ぎますが、コンストラクタとデストラクタは例外で継承されません。基本クラスの初期化を行うのは、あくまで基本クラスのコンストラクタです。派生クラスのインスタンスを初期化するには、それよりも前に基本クラスの初期化が終了していなければなりません。派生クラスのインスタンスが生成されるとき、先に基本クラスのインスタンスを初期化するために、暗黙的に基本クラスのコンストラクタが実行されます。
クラスのインスタンスが生成されるときにコンストラクタが呼び出されますが、派生クラスのコンストラクタは、コンストラクタ内の最初の文が実行されるよりも先に、基本クラスのコンストラクタを暗黙的に呼び出します。従って、継承関係にあるクラスは常に基本クラスのコンストラクタから派生クラスのコンストラクタの順番で実行されることになります。
class PrettyCure { public PrettyCure() { System.Console.Write("プリキュア - "); } } class HeartCatchPreCure : PrettyCure { public HeartCatchPreCure() { System.Console.WriteLine("オープンマイハート!"); } } class SmilePreCure : PrettyCure { public SmilePreCure() { System.Console.WriteLine("スマイルチャージ!"); } } class Test { public static void Main(string[] args) { HeartCatchPreCure prettyCure1 = new HeartCatchPreCure(); SmilePreCure prettyCure2 = new SmilePreCure(); } }
コード1は PrettyCure クラスを基本クラスとする HeartCatchPreCure クラスと SmilePreCure クラスを作成しています。Main() メソッドでこれら派生クラスのインスタンスを生成し、コンストラクタがどのような順番で実行されるかを確認しています。実行結果を見れば、先に基本クラスである PrettyCure クラスのコンストラクタから実行されていることが確認できます。
この関係はクラスが何段階に継承されても同じです。常に、最上位の基本クラスのコンストラクタから実行され派生順に実行されます。
暗黙的に呼び出される基本クラスのコンストラクタは、パラメータを受け取らない既定のコンストラクタのみです。基本クラスのコンストラクタがパラメータを受け取る場合、派生クラスのコンストラクタから引数を渡す必要があります。この場合は、明示的に基底クラスのコンストラクタを呼び出す base キーワードを用いたコンストラクタ初期化子を指定します。
: base ( 引数リスト )
以前、オーバーロードされた別のコンストラクタを呼び出すための this キーワードを用いたコンストラクタ初期化子を説明しました。base コンストラクタ初期化子も構文は同じで、基本クラスのコンストラクタを明示的に呼び出すために用いられます。
class PrettyCure { public PrettyCure(string ready) { System.Console.WriteLine("プリキュア - " + ready); } } class HeartCatchPreCure : PrettyCure { public HeartCatchPreCure() : base ("オープンマイハート!") {} } class SmilePreCure : PrettyCure { public SmilePreCure() : base("スマイルチャージ!") {} } class Test { public static void Main(string[] args) { HeartCatchPreCure prettyCure1 = new HeartCatchPreCure(); SmilePreCure prettyCure2 = new SmilePreCure(); } }
コード2は PrettyCure クラスと、PrettyCure クラスを継承する HeartCatchPreCure クラスと SmilePreCure クラスを作成しています。PrettyCure クラスのコンストラクタは string 型のパラメータを要求しているため、派生クラスのコンストラクタはコンストラクタ初期化子を用いて明示的に基本クラスのコンストラクタを呼び出さなければなりません。HeartCatchPreCure クラスと SmilePreCure クラスは、base コンストラクタ初期化子を用いてリテラル文字列を基本クラスのコンストラクタに渡しています。
デストラクタの実行順序
コンストラクタと同様に、デストラクタも継承されません。そのクラスの破棄を行うのは、そのクラス自身のデストラクタのみです。デストラクタの実行はコンストラクタとは逆に、派生クラスから基本クラスに向かって実行されます。従って、派生クラスのデストラクタ内で基本クラスの機能にアクセスすることは可能です。
class PrettyCure { ~PrettyCure() { System.Console.WriteLine("プリキュア!"); } } class HeartCatchPreCure : PrettyCure { ~HeartCatchPreCure() { System.Console.Write("世界に輝く一面の花! ハートキャッチ "); } } class SuitePreCure : PrettyCure { ~SuitePreCure() { System.Console.Write("届け、ふたりの組曲! スイート "); } } class Test { public static void Main(string[] args) { HeartCatchPreCure prettyCure1 = new HeartCatchPreCure(); SuitePreCure prettyCure2 = new SuitePreCure(); } }
コード3は PrettyCure クラスと、これを継承する HeartCatchPreCure クラス及び SuitePreCure クラスを作成し、それぞれにデストラクタを宣言しています。各デストラクタ内で文字列を出力しているため、結果から派生クラスのデストラクタが先に実行されていることが確認できます。