講義メモ

・p.264「interface04.cs」から

p.264 複数のインターフェイスを実装する(同じシグニチャの場合):再掲載

・複数の同じシグニチャの抽象メンバをもつインターフェイスを実装することができる
・この場合、インターフェイスを型とする参照変数を定義して用いると良い
・書式: インターフェイスを型とする参照変数.メソッド名(引数)

補足:p.264 interface04.cs

・005行目:publicは不要
・010行目:publicは不要

p.265 interface05.cs

//p.265 interface05.cs
using System;
interface IMas { //インターフェイス①「です・ます」の定義
    void show(int i); //抽象メソッド①の定義
}
public interface IDa { //インターフェイス②「だ・である」の定義
    void show(int i); //抽象メソッド②の定義 ※①と同じシグニチャ
}
class MyClass : IMas, IDa { //インターフェイス①②を実装するクラス
    void IMas.show(int i) { //インターフェイス①名を前置した抽象メソッド①のオーバーライド「です」
        Console.WriteLine("iは{0}です", i);
    }
    void IDa.show(int i) { //インターフェイス②名を前置した抽象メソッド②のオーバーライド「だ」
        Console.WriteLine("iは{0}だ", i);
    }
}
class interface05 {
    public static void Main() {
        IMas im; //インターフェイス①型の参照変数
        IDa id; //インターフェイス②型の参照変数
        MyClass mc = new MyClass(); //インターフェイス①②を実装するクラスのオブジェクトを生成
        im = mc; //インターフェイス①型の参照変数に代入すると
        im.show(5); //抽象メソッド①のオーバーライド「です」が呼ばれる
        id = mc; //インターフェイス②型の参照変数に代入すると
        id.show(5); //抽象メソッド②のオーバーライド「だ」が呼ばれる
    }
}

アレンジ演習:p.265 interface05.cs

・インターフェイスを実装するクラスのオブジェクトは、インターフェイス型にキャストすることで、インターフェイス型の参照変数で扱える
・このことを活用して、シンプルにしよう
・なお、キャストの優先順位は低くドットの優先順位は高いので、カッコで優先させること
・書式例: ((インターフェイス名)参照変数名).メソッド名(引数,…)

作成例

//p.265 interface05.cs
using System;
interface IMas { //インターフェイス①「です・ます」の定義
    void show(int i); //抽象メソッド①の定義
}
public interface IDa { //インターフェイス②「だ・である」の定義
    void show(int i); //抽象メソッド②の定義 ※①と同じシグニチャ
}
class MyClass : IMas, IDa { //インターフェイス①②を実装するクラス
    void IMas.show(int i) { //インターフェイス①名を前置した抽象メソッド①のオーバーライド「です」
        Console.WriteLine("iは{0}です", i);
    }
    void IDa.show(int i) { //インターフェイス②名を前置した抽象メソッド②のオーバーライド「だ」
        Console.WriteLine("iは{0}だ", i);
    }
}
class interface05 {
    public static void Main() {
        MyClass mc = new MyClass(); //インターフェイス①②を実装するクラスのオブジェクトを生成
        ((IMas)mc).show(5); //【変更】抽象メソッド①のオーバーライド「です」が呼ばれる
        ((IDa)mc).show(5); //【変更】抽象メソッド②のオーバーライド「だ」が呼ばれる
    }
}

p.266 インターフェイスの継承

・クラスがクラスを継承できると同様に、インターフェイスがインターフェイスを継承できる
・これにより、インターフェイスの乱立を防ぐことができる
・継承される基本インタフェースの抽象メンバは、派生インターフェイスに引き継がれる
・定義書式: interface 派生インターフェイス名 : 基本インタフェース名 {…}
※ 継承なので、複数の基本インタフェースを指定することはできない(実装にはならない)

p.266 interface06.cs

//p.266 interface06.cs
using System;
interface IInterface1 { //基本インタフェース
    void setdatano(int n); //抽象メソッド①
    void setdata(double data, int i); //抽象メソッド②
    double calcsum(); //抽象メソッド③
}
interface IInterface2 : IInterface1 { //派生インターフェイス
    //ここに抽象メソッド①「void setdatano(int n);」が継承されている
    //ここに抽象メソッド②「void setdata(double data, int i);」が継承されている
    //ここに抽象メソッド③「double calcsum();」が継承されている
    double calcaverage(); //このインターフェイス独自の抽象メソッド④
}
class MyClass : IInterface2 { //派生インターフェイスを実装するクラス
    double[] data; //実数型配列の宣言
    bool bOK = false; //OKフラグをオフにしておく
    public void setdatano(int n) { //抽象メソッド①のオーバーライド
        data = new double[n]; //引数を要素数として実数型配列を生成
        bOK = true; //OKフラグをオンにする
    }
    public void setdata(double d, int i) { //抽象メソッド②のオーバーライド
        if (!bOK) { //OKフラグがオフであれば
            Console.WriteLine("配列の準備ができていません");
            return; //何もしない
        }
        data[i] = d; //引数dを要素値、iを添字として配列に格納
    }
    public double calcsum() { //抽象メソッド③のオーバーライド
        if (!bOK) { //OKフラグがオフであれば
            Console.WriteLine("配列の準備ができていません");
            return -1.0; //何もしない(仮の値を返す)
        }
        double sum = 0.0; //合計を0にする
        for (int i = 0; i < data.Length; i++) { //全要素について繰返す
            sum += data[i]; //合計に足し込む
        }
        return sum; //合計を返す
    }
    public double calcaverage() { //抽象メソッド④のオーバーライド
        double sum = calcsum(); //合計計算を呼ぶ
        return sum / data.Length; //合計を件数で割って平均を得て返す
    }
}
class interface06 {
    public static void Main() {
        MyClass mc = new MyClass(); //派生インターフェイスを実装するクラスのオブジェクトを生成
        int nNo; //入力用
        while (true) { //無限ループ
            Console.Write("データ数---");
            string strno = Console.ReadLine();
            nNo = Int32.Parse(strno); //整数変換
            mc.setdatano(nNo); //データ数を要素数とする配列を生成
            for (int i = 0; i < nNo; i++) { //データ数について繰返す
                Console.Write("data[{0}] = ", i); //添字を表示
                string strdata = Console.ReadLine();
                mc.setdata(double.Parse(strdata), i); //実数に変換して配列に格納
            }
            Console.WriteLine("合計 = {0}", mc.calcsum());
            Console.WriteLine("平均 = {0}", mc.calcaverage());
            Console.WriteLine();
            Console.Write("続けますか(Y/N)---");
            string yn = Console.ReadLine();
            if (yn == "N" || yn == "n") {
                break;
            }
        }
    }
}

p.270(インターフェイスの継承と名前の隠ぺい)

・派生インターフェイスの抽象メンバと同じシグニチャの仮想メンバがある場合、名前の隠ぺいになる
・よって、newキーワードを前置して、名前の隠ぺいを明示する

p.270 interface07.cs

//p.270 interface07.cs
using System;
interface IMyInterface { //基本インタフェース
    void show1(); //抽象メソッド①
    void show2(); //抽象メソッド②
}
interface IMyInterface2 : IMyInterface { //派生インターフェイス
    //ここに抽象メソッド①が継承されるが、名前の隠ぺいの対象になる
    new void show1(); //抽象メソッド①の名前を隠ぺいする抽象メソッド①'
    //ここに抽象メソッド②が継承される
    void show3(); //抽象メソッド③
}
class MyClass : IMyInterface2 { //派生インターフェイスを実装するクラス
    public void show1() { //抽象メソッド①'のオーバーライド
        Console.WriteLine("show1");
    }
    public void show2() { //抽象メソッド②のオーバーライド
        Console.WriteLine("show2");
    }
    public void show3() { //抽象メソッド③のオーバーライド
        Console.WriteLine("show3");
    }
}
class interface07 {
    public static void Main() {
        MyClass mc = new MyClass(); //派生インターフェイスを実装するクラス
        mc.show1(); //抽象メソッド①'のオーバーライドを呼ぶ
        mc.show2(); //抽象メソッド② のオーバーライドを呼ぶ
        mc.show3(); //抽象メソッド③ のオーバーライドを呼ぶ
    }
}

アレンジ演習:p.270 interface07.cs

・派生インターフェイスにおいて、基本クラスの抽象メソッドと同じシグニチャで戻り値型が異なる抽象メソッドを定義できる
・しかし、この派生インターフェイスを実装するクラスはエラーになってしまう
・その理由を考えよう

作成例

//アレンジ演習:p.270 interface07.cs
using System;
interface IMyInterface { //基本インタフェース
    void show1(); //抽象メソッド①
    void show2(); //抽象メソッド②
}
interface IMyInterface2 : IMyInterface { //派生インターフェイス
    //ここに抽象メソッド①が継承されるが、名前の隠ぺいの対象になる
    new void show1(); //抽象メソッド①の名前を隠ぺいする抽象メソッド①'
    //ここに抽象メソッド②が継承される
    new int show2(); //【追加】抽象メソッド②と同じシグニチャだが戻り値型が異なる抽象メソッド②'
    void show3(); //抽象メソッド③
}
class MyClass : IMyInterface2 { //派生インターフェイスを実装するクラス
    public void show1() { //抽象メソッド①'のオーバーライド
        Console.WriteLine("show1");
    }
    public void show2() { //抽象メソッド②のオーバーライド
        Console.WriteLine("show2");
    }
    public int show2() { //【追加】抽象メソッド②'のオーバーライド⇒戻り値型が異なるが同じシグニチャなのでエラー
        Console.WriteLine("show2");
    }
    public void show3() { //抽象メソッド③のオーバーライド
        Console.WriteLine("show3");
    }
}
class interface07 {
    public static void Main() {
        MyClass mc = new MyClass(); //派生インターフェイスを実装するクラス
        mc.show1(); //抽象メソッド①'のオーバーライドを呼ぶ
        mc.show2(); //抽象メソッド② のオーバーライドを呼ぶ ※ここもエラーになる
        mc.show3(); //抽象メソッド③ のオーバーライドを呼ぶ
    }
}

p.272(インターフェイスの継承と名前の隠ぺいと明示的実装)

・名前の隠ぺいを行っている派生インターフェイスでは、派生クラスの場合と同様に、実装時に隠ぺいされたメンバもオーバライドできる
・これは(baseキーワードではなく)、複数のインターフェイスをクラスが実装する時に同じシグニチャがある場合と同様に「インターフェイス名.」を前置すれば良い
・そして、そのクラスのインスタンスを用いる時に、インターフェイスを型とする参照変数を定義して用いると良い

p.272 interface08.cs

//p.272 interface08.cs
using System;
interface I1 { //基本インターフェイス
    void show1(); //抽象メソッド①
    void show2(); //抽象メソッド②
}
interface I2 : I1 { //派生インターフェイス
    //ここに「void show1();」/抽象メソッド②が継承されるが名前の隠ぺいの対象になる
    new void show1(); //抽象メソッド①の名前の隠ぺいをする抽象メソッド①'
    //ここに「void show2();」/抽象メソッド②が継承される
}
class MyClass : I2 { //派生インターフェイスを実装するクラス
    void I1.show1() { //基本インターフェイス名を前置して抽象メソッド①のオーバライド
        Console.WriteLine("I1.show1");
    }
    void I2.show1() { //派生インターフェイス名を前置して抽象メソッド①'のオーバライド
        Console.WriteLine("I2.show1");
    }
    public void show2() { //基本インターフェイスの抽象メソッド②のオーバライド
        Console.WriteLine("show2");
    }
}
class interface08 {
    public static void Main() {
        MyClass mc = new MyClass(); //派生インターフェイスを実装するクラスのオブジェクトを生成
        I1 i1; //基本インターフェイスを型とする参照変数①
        I2 i2; //派生インターフェイスを型とする参照変数②
        mc.show2(); //基本インターフェイスの抽象メソッド②のオーバライドを呼ぶ
        i1 = mc; //基本インターフェイスを型とする参照変数①にクラスのオブジェクトの参照を代入
        i1.show1(); //基本インターフェイスに対応する抽象メソッド①のオーバライドを呼ぶ
        i2 = mc; //派生インターフェイスを型とする参照変数②にクラスのオブジェクトの参照を代入
        i2.show1(); //派生インターフェイスに対応する抽象メソッド①'のオーバライドを呼ぶ
        i2.show2(); //mc.show2()と同じ
    }
}

アレンジ演習:p.272 interface08.cs

・意味が分かりづらいので、下記に置き換えて考えよう
 ・interface I1 ⇒ interface skyfly //空を飛べる
  ・void show1(); void howtofly() //飛び方を表示(空用)
  ・void show2(); void sound() //飛ぶ時の音を表示
 ・interface I2 ⇒ interface spacefly //宇宙を飛べる(空を飛べるを継承)
  ・void show1(); void howtofly()//飛び方を表示(宇宙用)
 ・class MyClass ⇒ class SpaceDragon : spacefly //宇宙を飛べる宇宙竜
 ・class interface08 も上記に合わせてアレンジしよう

作成例

//アレンジ演習:p.272 interface08.cs
using System;
interface skyfly { //基本インターフェイス「空を飛べる」
    void howtofly(); //抽象メソッド①飛び方を表示(空用)
    void sound(); //抽象メソッド②飛ぶ時の音を表示
}
interface spacefly : skyfly { //派生インターフェイス「宇宙を飛べる(空を飛べるを継承)」
    //ここに「void howtofly();」/抽象メソッド①が継承されるが名前の隠ぺいの対象になる
    new void howtofly(); //抽象メソッド①の名前の隠ぺいをする抽象メソッド①'飛び方を表示(宇宙用)
    //ここに「void sound();」/抽象メソッド②が継承される
}
class SpaceDragon : spacefly { //派生インターフェイス「宇宙を飛べる(空を飛べるを継承)」を実装するクラス「宇宙竜」
    void skyfly.howtofly() { //抽象メソッド①のオーバライド
        Console.WriteLine("翼で空気を受けて飛ぶ"); //飛び方を表示(空用)
    }
    void spacefly.howtofly() { //抽象メソッド①'のオーバライド
        Console.WriteLine("エネルギーを出して飛ぶ"); //飛び方を表示(宇宙用)
    }
    public void sound() { //基本インターフェイスの抽象メソッド②のオーバライド
        Console.WriteLine("ギューン"); //飛ぶ時の音
    }
}
class interface08 {
    public static void Main() {
        SpaceDragon Veldra = new SpaceDragon(); //派生インターフェイスを実装するクラスのオブジェクトを生成
        skyfly Skyfling; //基本インターフェイスを型とする参照変数①
        spacefly Spaceflying; //派生インターフェイスを型とする参照変数②
        Veldra.sound(); //基本インターフェイスの抽象メソッド②のオーバライドを呼ぶ
        Skyfling = Veldra; //基本インターフェイスを型とする参照変数①にクラスのオブジェクトの参照を代入
        Skyfling.howtofly(); //基本インターフェイスに対応する抽象メソッド①のオーバライドを呼ぶ
        ((skyfly)Veldra).howtofly(); //上記はこうしてもOK
        Spaceflying = Veldra; //派生インターフェイスを型とする参照変数②にクラスのオブジェクトの参照を代入
        Spaceflying.howtofly(); //派生インターフェイスに対応する抽象メソッド①'のオーバライドを呼ぶ
        ((spacefly)Veldra).howtofly(); //上記はこうしてもOK
        Spaceflying.sound(); //Veldra.sound()と同じ
    }
}

p.274 練習問題1 ヒント

・抽象メソッド int Count(string str) を持つインターフェイスを定義しよう
・このインターフェイスを実装するクラスを定義しよう
・このクラスの中で抽象メソッドをオーバーライドして、引数strで得られる文字列の長さ(p.73)を返す処理を記述
・実行用クラスとMainメソッドを記述し、上記のクラスのインスタンスを生成し、Countメソッドに文字列を与えよう
・Countメソッドの戻り値を表示して確認しよう

作成例

//p.274 練習問題1
using System;
interface Countable { //インターフェイス「数えられる」
    int Count(string str); //抽象メソッド「文字列の文字数を返す」
}
class CountStrings : Countable { //インターフェイスを実装するクラス「数えられる文字列」
    public int Count(string str) { //抽象メソッド「文字列の文字数を返す」のオーバライド
        return str.Length; //文字数を返す
    }
}
class ex1001 {
    public static void Main() {
        CountStrings wordcount = new CountStrings(); //インターフェイスを実装するクラスのオブジェクトを生成
        string word = "ABC";
        Console.WriteLine("{0}は{1}文字です", word, wordcount.Count(word));
    }
}

p.254 練習問題1 ヒント

・仮想メソッドCalcは「2つのint型の引数をとり、その和を返す」のだから、シグニチャは
 int Calc(int ●, int ▲);
・クラスA1は仮想メソッドCalcを持ち、●+▲を返す
・クラスA2はクラスA1を継承する
・クラスA2は継承したメソッドCalcをオーバーライドし、●-▲を返す
・Mainでは:
 ① クラスA2のインスタンスを生成
 ② ①の参照変数.Calcメソッドの実行結果を表示(例:Calc(5, 8)) ⇒ 差になる
 ③ クラスA1型の参照変数を①の参照変数で初期化
 ④ ③の参照変数.Calcメソッドの実行結果を表示(例:Calc(5, 8)) ⇒ やはり差になる(多態性)

作成例

//p.254 練習問題1
using System;
class A1 { //基本クラス
    public virtual int Calc(int a, int b) { //オーバライド可能な仮想メソッド
        return a + b; //和を返す
    }
}
class A2 : A1 { //派生クラス
    public override int Calc(int a, int b) { //オーバライドメソッド
        return a - b; //差を返す
    }
}
class ex0901 {
    public static void Main() {
        A2 a2 = new A2(); //派生クラスA2のインスタンスを生成
        Console.WriteLine(a2.Calc(5, 8)); //オーバライドメソッドを実行
        A1 a1 = a2; //A1型変数a1を宣言して。A2への参照a2を代入
        Console.WriteLine(a1.Calc(5, 8)); //仮想メソッドを実行しても…
    }
}

以上です。お疲れ様でした。

コメントを残す

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