#51 コンストラクタと継承

こんにちは。
最近、間が開きっぱなしのエントリーは良くないなと思い、今週2回目のトピックです(`・ω・´)

本日は、コンストラクタについてです。
コンストラクタ - Wikipedia



オブジェクトを生成する時に、コンストラクタを実行します。

もし継承を行っていれば、上位クラスもコンストラクタを持っているはずです。
その時、どのような動きをするのでしょうか?

今回は、そこに着目して、C#で実験してみました。



実験に使う、一番ベースとなるクラスです。
public class BaseClass
{
    public BaseClass()
    {
        Console.WriteLine("BaseClass");
    }

    public BaseClass(int x)
    {
        Console.WriteLine("{0}:BaseClass", x);
    }
}
これ以降に紹介する下位クラスたちも、この2種類のコンストラクタを持ちます。


ちなみに、サンプルコードと実行結果は次のようになります。
// サンプルコード
BaseClass bs = new BaseClass();
[ 実行結果 ]
BaseClass
// サンプルコード
BaseClass bs = new BaseClass(0);
[ 実行結果 ]
0:BaseClass
では、下位クラスの1番目です。
public class SubClass1 : BaseClass
{
    public SubClass1()
    {
        Console.WriteLine("SubClass1");
    }

    public SubClass1(int x)
    {
        Console.WriteLine("{0}:SubClass1", x);
    }
}
特に工夫のない、シンプルな継承です。


サンプルコードを見ていきましょう。
// サンプルコード 1-1
SubClass1 sc1 = new SubClass1();

// サンプルコード 1-2
SubClass1 sc1 = new SubClass1(1);
実行結果は次の通りです。

[ 実行結果 1-1 ]
BaseClass
SubClass1
[ 実行結果 1-2 ]
BaseClass
1:SubClass1
下位クラスでコンストラクタを実行すると、上位クラスのコンストラクタを実行してから、下位クラスの処理を行うようです。
また、引数指定のコンストラクタを下位クラスが実行しても、上位クラスの処理はデフォルトのものが行われています。



続いて、下位クラスの2番目です。
public class SubClass2 : BaseClass
{
    public SubClass2()
        : base()
    {
        Console.WriteLine("SubClass2");
    }

    public SubClass2(int x)
        : base(x)
    {
        Console.WriteLine("{0}:SubClass2", x);
    }
}
下位クラス1との違いは、明示的に上位クラスのコンストラクタを指定していることです。
// サンプルコード 2-1
SubClass2 sc2 = new SubClass2();

// サンプルコード 2-2
SubClass2 sc2 = new SubClass2(2);
さて、このサンプルコードを実行すると、どうなるでしょうか。

[ 実行結果 2-1 ]
BaseClass
SubClass2
[ 実行結果 2-2 ]
2:BaseClass
2:SubClass2
このように、引数指定のコンストラクタで、上位の処理も引数指定時のものになっています。



ここからは、この下位クラス1と2をそれぞれ継承した孫クラスたちです。
まずは、下位クラス3から。
public class SubClass3 : SubClass1
{
    public SubClass3()
    {
        Console.WriteLine("SubClass3");
    }

    public SubClass3(int x)
    {
        Console.WriteLine("{0}:SubClass3", x);
    }
}
基本クラスを単純継承した下位クラス1を、さらに単純に継承しています。
シンプルなコードって、とても好感が持てます(・∀・)
// サンプルコード 3-1
SubClass3 sc3 = new SubClass3();

// サンプルコード 3-2
SubClass3 sc3 = new SubClass3(3);
サンプルコードを実行してみます。

[ 実行結果 3-1 ]
BaseClass
SubClass1
SubClass3
[ 実行結果 3-2 ]
BaseClass
SubClass1
3:SubClass3
やはり引数付きコンストラクタでは、上位の処理にてデフォルト処理が行われていますね。



下位クラス4です。
public class SubClass4 : SubClass1
{
    public SubClass4()
        : base()
    {
        Console.WriteLine("SubClass4");
    }

    public SubClass4(int x)
        : base(x)
    {
        Console.WriteLine("{0}:SubClass4", x);
    }
}
基本 →(単純)→ 下位1 →(明示)→ 下位4、という流れです。
// サンプルコード 4-1
SubClass4 sc4 = new SubClass4();

// サンプルコード 4-2
SubClass4 sc4 = new SubClass4(4);
実行してみましょう。

[ 実行結果 4-1 ]
BaseClass
SubClass1
SubClass4
[ 実行結果 4-2 ]
BaseClass
4:SubClass1
4:SubClass4
下位クラス4で引数付きコンストラクタを、明示的に上位(=下位クラス1)の引数付きのものを指定したので、そこでは引数付きの処理結果になっています。
しかし、下位クラス1の引数付きコンストラクタは、上位の処理はデフォルトなので、下位クラス4でも基本クラスの処理はデフォルトです。



残り2つは下位クラス2を継承したクラスたちです。
下位クラス5の定義です。
public class SubClass5 : SubClass2
{
    public SubClass5()
    {
        Console.WriteLine("SubClass5");
    }

    public SubClass5(int x)
    {
        Console.WriteLine("{0}:SubClass5", x);
    }
}
似たような定義ばかりで、そろそろ見飽きてきました・・・(*´д`)=3
// サンプルコード 5-1
SubClass5 sc5 = new SubClass5();

// サンプルコード 5-2
SubClass5 sc5 = new SubClass5(5);
じゃ、ちょちょいと実行してみますか。

[ 実行結果 5-1 ]
BaseClass
SubClass2
SubClass5
[ 実行結果 5-2 ]
BaseClass
SubClass2
5:SubClass5
やはり、違いは引数付きに出てきました。
親である下位クラス2は、引数付きコンストラクタで明示的に基本クラスの引数付きを指定しています。
しかし、下位クラス5の引数付きでは指定していないので、下位クラス2の処理ではデフォルトのコンストラクタが呼ばれています。



ラストは下位クラス6です。
public class SubClass6 : SubClass2
{
    public SubClass6()
        : base()
    {
        Console.WriteLine("SubClass6");
    }

    public SubClass6(int x)
        : base(x)
    {
        Console.WriteLine("{0}:SubClass6", x);
    }
}
祖から末代まで、全て明示的に上位のコンストラクタを指定しています。
// サンプルコード 6-1
SubClass6 sc6 = new SubClass6();

// サンプルコード 6-2
SubClass6 sc6 = new SubClass6(6);
これを実行してみると。。。

[ 実行結果 6-1 ]
BaseClass
SubClass2
SubClass6
[ 実行結果 6-2 ]
6:BaseClass
6:SubClass2
6:SubClass6
まるで、お祖父ちゃんから孫までが、一致団結して何かに取り組んでいるようにさえ見えてきます(笑)




このように、コンストラクタは上位のコンストラクタも実行し、さらに定義の仕方によって、どのコンストラクタを実行するかも決定できます。
このあたりは、継承の設計と合わせて考慮しておきたいところですね。


次回ですが、とりあえずF#です。
パターンマッチのお勉強をしてみようと思います。

なお、とりあえず、と言ったのは次回予告をどうしようか決めかねているからでして、もしかしたら予告の内容と実際の次回のトピックが異なる場合がありますw

トラックバックURL

#51 コンストラクタと継承 へのトラックバック

まだトラックバックはありません。

#51 コンストラクタと継承 へのコメント一覧

まだコメントはありません。

コメントする

#51 コンストラクタと継承 にコメントする
絵文字
プロフィール
あわせて読みたい
あわせて読みたい
記事検索
Project Euler
なかのひと
アクセス解析
Coderwall
  • ライブドアブログ

トップに戻る