講義メモ 後半

p.232 多態性

・クラスの継承は基本クラスを代表とする派生クラスのグルーピングにもなる
・例: Slimeクラスを継承するHoimiSlimeクラス、MetalSlimeクラスは「スライムの一族」
・よって、派生クラスのオブジェクトは、基本クラスを型とする変数に代入できる
・例: HoimiSlimeクラスのホイミンは、Slimeクラスのホイミンとしても扱える(メンバを引き継いでいるので)
・このとき、メソッドにおいて名前の隠蔽が起こっていると、基本クラスを型とする変数でメソッドを呼ぶと、基本クラスのメソッドが実行される
・しかし、メソッドにおいてオーバーライドが起こっていると、基本クラスを型とする変数でメソッドを呼んでも、
 派生クラスのオーバーライドメソッドが実行される
・このことを多態性(ポリモフィズム)という
・例: Slimeクラスの仮想メソッドはHPのみ表示、継承するHoimiSlimeクラスのオーバライドメソッドはHPとMPを表示する場合:
 HoimiSlimeクラスのホイミンは、Slimeクラスのホイミンとして扱っても、メソッドを呼ぶとオーバライドメソッドが動作してHPとMPを表示
・この「どのメソッドが実行されるかが実行時に決まる仕組み」を動的メソッドディスパッチャという
・例:
class Slime { //基本クラス
    int hp; //基本クラスのインスタンス変数メンバ
    public virtual void show() { //仮想メソッド
        Console.Write(hp); 
    }
}
class HoimiSlime : Slime { //派生クラス
    // ここに「int hp; //基本クラスのインスタンス変数メンバ」があるとみなされる
    int mp;
    // ここに「public virtual void show() {…} //基本クラスの仮想メソッド」があるがオーバーライドされる
    public override void show() { //オーバーライドメソッド
        Console.Write(hp + ", " + mp);
    }
}
HoimiSlime hoimin = new HoimiSlime();  //ホイミンをホイミスライムとして生成
Slime slime1 = hoimin; //ホイミンをスライムクラスのスライム1号として扱う
slime1.show(); //スライム1号はSlimeだが、多態性により中身がホイミンと分かりオーバライドメソッドが呼ばれる

アレンジ演習:p.233 override02.cs

・名前の隠ぺいでは(オーバーライドは異なり)多態性が起こらないことを確認しよう
・Dogクラスに名前を隠ぺいするLeg()メソッドを追加し「return 0;」としてみよう

作成例

//アレンジ演習:p.233 override02.cs
using System;
class Mammal { //基本クラス「哺乳類」
    protected const int LegNo = 4; //継承可能なインスタンス変数(定数)
    protected string Koe; //継承可能なインスタンス変数
    public virtual string Nakigoe() { //オーバーライド可能な仮想メソッド
        Koe = "..."; //哺乳類の鳴き声は様々なので
        return Koe; 
    }
    public int Leg() { //足の数を返す通常メソッド
        return LegNo; //定数値を返す
    }
}
class Cat : Mammal { //派生クラス「猫」
    public override string Nakigoe() { //オーバライドメソッド
        Koe = "ニャー、ニャー"; //鳴き声が確定
        return Koe;
    }
}
class Dog : Mammal { //派生クラス「犬」
    public override string Nakigoe() { //オーバライドメソッド
        Koe = "ワン、ワン"; //鳴き声が確定
        return Koe;
    }
    new public int Leg() { //【以下追加】足の数を返す通常メソッドの名前の隠ぺい
        return 0; //仮に0を返す ※多態性により用いられない
    }
}
class override02 {
    public static void Main() {
        Mammal m; //基本クラス「哺乳類」型の変数の宣言
        Cat cat = new Cat(); //派生クラス「猫」のインスタンスを生成
        Dog dog = new Dog(); //派生クラス「犬」のインスタンスを生成
        m = cat; //「猫」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("猫の脚は{0}本で鳴き声は「{1}」です", 
            m.Leg(), m.Nakigoe()); //鳴き声は多態性により「猫」になる
        m = dog; //「犬」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("犬の脚は{0}本で鳴き声は「{1}」です",
            m.Leg(), m.Nakigoe()); //鳴き声は多態性により「犬」になるが、足の数は変わらず4のまま
    }
}

p.235 プロパティのオーバーロード

・シグニチャ(プロパティ名)が同じプロパティを派生クラスに定義してオーバーライドすることが可能
・多態性(ポリモフィズム)が発生する

アレンジ演習:p.236 override03.cs

・プロパティにおいても、名前の隠ぺいでは(オーバーライドは異なり)多態性が起こらないことを確認しよう
・MammalクラスのLeg()メソッドをプロパティ(getのみ)に変更する。
・Dogクラスに名前を隠ぺいするLeg()プロパティ(getのみ)を追加し「return 0;」としてみよう

作成例

//アレンジ演習:p.236 override03.cs
using System;
class Mammal { //基本クラス「哺乳類」
    protected const int LegNo = 4; //継承可能なインスタンス変数(定数)
    public virtual string Nakigoe { //オーバーライド可能な仮想プロパティ
        get {
            return "...";
        }
    }
    public int Leg { //【変更】足の数を返す通常プロパティ
        get { //【追加】
            return LegNo; //定数値を返す
        }
    }
}
class Cat : Mammal { //派生クラス「猫」
    public override string Nakigoe { //オーバーライドプロパティ
        get {
            return "ニャー、ニャー";
        }
    }
}
class Dog : Mammal { //派生クラス「犬」
    public override string Nakigoe { //オーバーライドプロパティ
        get {
            return "ワン、ワン";
        }
    }
    new public int Leg { //【以下追加】足の数を返すプロパティの名前の隠ぺい
        get {
            return 0; //定数値を返す ※多態性により用いられない
        }
    }
}
class override03 {
    public static void Main() {
        Mammal m; //基本クラス「哺乳類」型の変数の宣言
        Cat cat = new Cat(); //派生クラス「猫」のインスタンスを生成
        Dog dog = new Dog(); //派生クラス「犬」のインスタンスを生成
        m = cat; //「猫」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("猫の脚の数は{0}本で、鳴き声は「{1}」です",
            m.Leg, m.Nakigoe); //【変更】鳴き声は多態性により「猫」になる
        m = dog; //「犬」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("犬の脚の数は{0}本で、鳴き声は「{1}」です",
            m.Leg, m.Nakigoe); //【変更】鳴き声は多態性により「犬」になる、足の数は変わらず4のまま
        //【以下参考までに追加】
        Console.WriteLine("dog.Leg = {0}", dog.Leg); //名前の隠ぺいをするプロパティが呼ばれる
    }
}

p.237 インデクサのオーバーロード

・シグニチャ(引数の型、数、並び)が同じインデクサを派生クラスに定義してオーバーライドすることが可能
・多態性(ポリモフィズム)が発生する

アレンジ演習:p.237 override04.cs

・インデクサにおいても、名前の隠ぺいでは(オーバーライドは異なり)多態性が起こらないことを確認しよう
・MammalクラスのLeg()メソッドをthis[int]インデクサに変更する。
・Dogクラスに名前を隠ぺいするthis[int]インデクサを追加し「return 0;」としてみよう
・なお、このプログラムのswitch構文では、必須なはずのbreakがreturnがあれば不要(記述不可)なことが分かる

作成例

//アレンジ演習:p.237 override04.cs
using System;
class Mammal { //基本クラス「哺乳類」
    protected const int LegNo = 4; //継承可能なインスタンス変数(定数)
    protected string Tail, Gei, Food, Koe; //継承可能なインスタンス変数
    public virtual string this[string index] { //仮想インデクサ[string]
        get {
            return "...";
        }
    }
    public int this[int index] { //【変更】脚の数を返す通常インデクサ[int]
        get { //【追加】
            return LegNo; //定数値を返す ※多態性により用いられない
        }
    }
}
class Cat : Mammal { //派生クラス「猫」
    public override string this[string index] { //オーバライドインデクサ[string]
        get {
            switch (index) {
                case "尾":
                    Tail = "1本";
                    return Tail; //retrunがあればbreakは不要
                case "芸":
                    Gei = "できない";
                    return Gei; //retrunがあればbreakは不要
                case "鳴き声":
                    Koe = "ニャー、ニャー";
                    return Koe; //retrunがあればbreakは不要
                case "食べ物":
                    Food = "キャットフード";
                    return Food; //retrunがあればbreakは不要
                default:
                    return ""; //retrunがあればbreakは不要
            }
        }
    }
}
class Dog : Mammal{ //派生クラス「犬」
    public override string this[string index] { //オーバライドインデクサ[string]
        get {
            switch (index) {
                case "尾":
                    Tail = "1本";
                    return Tail;
                case "芸":
                    Gei = "できる";
                    return Gei;
                case "鳴き声":
                    Koe = "ワン、ワン";
                    return Koe;
                case "食べ物":
                    Food = "ドッグフード";
                    return Food;
                default:
                    return "";
            }
        }
    }
    new public int this[int index] { //【以下追加】脚の数を返す通常インデクサ[int]の名前の隠ぺい
        get {
            return 0;
        }
    }
}
class override04 {
    public static void Main() {
        Mammal m; //基本クラス「哺乳類」型の変数の宣言
        Cat cat = new Cat(); //派生クラス「猫」のインスタンスを生成
        Dog dog = new Dog(); //派生クラス「犬」のインスタンスを生成
        m = cat; //「猫」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("猫の脚は{0}本です。尾は{1}です。芸は{2}。食べ物は{3}。",
            m[0], m["尾"], m["芸"], m["食べ物"]); //【変更】脚以外は多態性により「猫」になる
        m = dog; //「犬」のインスタンスを「哺乳類」型の変数で扱う
        Console.WriteLine("犬の脚は{0}本です。尾は{1}です。芸は{2}。食べ物は{3}。",
            m[0], m["尾"], m["芸"], m["食べ物"]); //【変更】脚以外は多態性により「犬」になる
        //【以下参考までに追加】
        Console.WriteLine("dog.Leg = {0}", dog[0]); //名前の隠ぺいをするインデクサが呼ばれる
    }
}

p.240 クラスの多層階層

・派生クラスを基本クラスとして、さらに派生クラスを定義できる
・基本クラスのメンバは派生の派生クラスに継承される
・派生の派生クラスのオブジェクトも基本クラスの変数で扱える
・派生クラスで独自に記述したメソッドも、仮想メソッドにすることで、派生の派生クラスでオーバーライドできる
・派生クラスのオーバーライドメソッドを、そのまま、派生の派生クラスでオーバーライドできる
・つまり、オーバーライドメソッドの対象は上位のクラスの仮想メソッドまたはオーバーライドメソッド

アレンジ演習:p.240 inheritance05.cs

・派生クラスのオーバーライドメソッドを、そのまま、派生の派生クラスでオーバーライドできることを確認しよう
・Derived2クラスを継承するDerived3クラスを定義して、Show()メソッドをオーバーライドし、Main()で呼び出てみよう

提出:アレンジ演習:p.240 inheritance05.cs

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です