講義メモ

・p.266「インターフェイスの継承」から(※ 9章の練習問題も行います)

提出フォロー:ミニ演習 mini266.cs

・「アレンジ演習:p.265 interface05.cs」からIDaインターフェイスを除外して、動作を確認しよう

作成例

//ミニ演習 mini266.cs
using System;
interface IMas { //「です・ます」を示すインターフェイス
    void show(int i); //抽象メソッド①
}
abstract class Base { //抽象クラス
    public abstract void show(int i); //抽象メソッド②
}
class MyClass : Base, IMas { //抽象クラスを継承しインターフェイスを実装するクラス
    void IMas.show(int i) { //抽象メソッド①のオーバライドなので「です・ます」
        Console.WriteLine("iは{0}です", i);
    }
    public override void show(int i) { //抽象メソッド②のオーバライド
        Console.WriteLine("iは{0}", i);
    }
}
class interface05 {
    public static void Main() {
        IMas im; //インターフェイス型の変数
        MyClass mc = new MyClass(); //抽象クラスを継承しインターフェイスを実装するクラスのオブジェクト
        im = mc; //インターフェイス型の変数に代入して
        im.show(5); //抽象メソッド①のオーバライドを実行
        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; //生成済フラグをオフにする
    public void setdatano(int n) { //抽象メソッド①のオーバライド
        data = new double[n]; //引数で受け取った要素数の配列を生成
        bOK = true; //生成済フラグをオンにする
    }
    public void setdata(double d, int i) { //抽象メソッド②のオーバライド
        if (!bOK) { //生成済フラグがオフ(未生成)?
            Console.WriteLine("配列の準備ができていません");
            return;
        }
        data[i] = d; //引数で受け取った値と添字で配列に格納
    }
    public double calcsum() { //抽象メソッド③のオーバライド
        if (!bOK) { //生成済フラグがオフ(未生成)?
            Console.WriteLine("配列の準備ができていません");
            return -1.0; //未済である旨を返す
        }
        double sum = 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); //「int.Parse」と同じ
            mc.setdatano(nNo); //要素数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;
            }
        }
    }
}

ミニ演習 mini267.cs

・派生インターフェイスを型とする変数を、基本インターフェイスを型とする変数で扱えるかどうか確認しよう
・基本インターフェイス: interface RunAble { void run(); }
・派生インターフェイス: interface FastRunAble { void fastrun(); }
・派生インターフェイスを実装するクラス: class Dragon : FastRunAble {…}

作成例

//ミニ演習 mini267.cs
using System;
interface RunAble { //基本インターフェイス
    void run(); //抽象メソッド①
}
interface FastRunAble  : RunAble { //派生インターフェイス
    //ここに「void run();//抽象メソッド①」があるとみなす
    void fastrun(); //抽象メソッド②
}
class Dragon : FastRunAble { //派生インターフェイスを実装するクラス
    public void run() { //抽象メソッド①のオーバライド
        Console.WriteLine("脚で走る");
    }
    public void fastrun() { //抽象メソッド②のオーバライド
        Console.WriteLine("翼と脚で走る");
    }
}
class mini267 {
    public static void Main() {
        FastRunAble Veldra = new Dragon(); //派生インターフェイスを型とする変数
        Veldra.fastrun(); //抽象メソッド②のオーバライドを呼ぶ
        RunAble Veldra2 = Veldra; //基本インターフェイスを型とする変数
        Veldra2.run(); //抽象メソッド①のオーバライドを呼ぶ
    }
}

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

・派生インターフェイスで、基本インターフェイスと同じシグニチャの仮想メンバを定義できる
・これは、クラスの継承の場合と同様に「名前の隠ぺい(p.228)」となる
・よって、newキーワードを前置して、名前の隠ぺいであることを明示すると良い

p.270 interface07.cs

//p.270 interface07.cs
using System;
interface IMyInterface { //基本インターフェイス
    void show1(); //抽象メソッド①
    void show2(); //抽象メソッド②
}
interface IMyInterface2 : IMyInterface { //派生インターフェイス
    //ここに「void show1(); //抽象メソッド①」があるとみなされるが隠ぺいされる
    //ここに「void show2(); //抽象メソッド②」があるとみなされる
    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(); //抽象メソッド③のオーバライドを呼ぶ
    }
}

ミニ演習 mini268.cs

・派生インターフェイスで、基本インターフェイスの抽象メソッドと同じシグニチャで戻り値型が異なる抽象メソッドを定義して
 名前の隠ぺいができるが、
 派生インターフェイスを実装するクラスで、戻り値型が異なる抽象メソッドのみをオーバライドすると
 エラーになることを確認しよう
・これを「インターフェイス名.メソッド名」で両方をオーバライドするとエラーが解消することを確認しよう
・基本インターフェイス: interface RunAble { void run(); }
・派生インターフェイス: interface FastRunAble { new int run(); }
・派生インターフェイスを実装するクラス: class Dragon : FastRunAble {…}
※ p.272 interface08.csでは戻り値型も同じ抽象メソッドで名前を隠ぺいしているが、
 実務的な必要性はあまりないので、この例で理解すると良い

作成例

//ミニ演習 mini268.cs
using System;
interface RunAble { //基本インターフェイス
    void run(); //抽象メソッド①
}
interface FastRunAble  : RunAble { //派生インターフェイス
    //ここに「void run();//抽象メソッド①」があるとみなすが隠ぺいされる
    new int run(); //抽象メソッド②
}
class Dragon : FastRunAble { //派生インターフェイスを実装するクラス
    void RunAble.run() { } //抽象メソッド①のオーバライド
    int FastRunAble.run() { //抽象メソッド②のオーバライド
        Console.WriteLine("脚で走る");
        return 100;
    }
}
class mini266 {
    public static void Main() {
        FastRunAble Veldra = new Dragon(); //派生インターフェイスを型とする変数
        int speed = Veldra.run(); //抽象メソッド②のオーバライドを呼ぶ
        Console.WriteLine("{0}km/h", speed);
    }
}

p.254 練習問題1・2 ヒント

・p.231 override01.csを基にすると良い
・Mainメソッドは下記のようにすると良い
 ① 派生クラスであるA2クラスのインスタンスを生成
 ② ①のCalcメソッドを実行し、差が得られることを確認
 ③ ①を基本クラスであるA1を型とする変数に代入
 ④ ③のCalcメソッドを実行し、和が得られるか差が得られるかを確認

作成例:p.254 練習問題1

//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 sampleclass {
    public static void Main() {
        A2 a = new A2(); //派生クラスのオブジェクトを生成
        Console.WriteLine("{0}",a.Calc(1,2)); //差を返すメソッドになる
        A1 b; //基本クラスを型とする変数を定義
        b = a; //派生クラスのオブジェクトを代入しても…
        Console.WriteLine("{0}",b.Calc(1,2)); //多態性により、差を返すメソッドになる
    }
}

作成例:p.254 練習問題2

//p.254 練習問題2
using System;
class A1 { //和を返すメソッドを持つ基本クラス
    public int Calc(int a,int b) { //通常のメソッドにする
        return a + b; //和を返す
    }
}
class A2 : A1 { //差を返すメソッドを持つ派生クラス
    new public int Calc(int a,int b) { //名前の隠ぺいとなるメソッド
        return a - b; //差を返す
    }
}
class sampleclass {
    public static void Main() {
        A2 a = new A2(); //派生クラスのオブジェクトを生成
        Console.WriteLine("{0}",a.Calc(1,2)); //差を返すメソッドになる
        A1 b; //基本クラスを型とする変数を定義
        b = a; //派生クラスのオブジェクトを代入すると
        Console.WriteLine("{0}",b.Calc(1,2)); //名前の隠ぺいにより、和を返すメソッドになる
    }
}

p.274 練習問題 ヒント

・文字列の文字数を返すには、Lengthプロパティ(p.73)を用いると良い
手順
① インターフェイス名は特に指定なしなので、仮にCountableとする
② ①の中に、抽象メソッド int Count(string str); を定義する
③ Countableインターフェイスを実装するクラス名も特に指定なしなので、仮にDragonとする
④ ③において、int Count(string str)メソッドをオーバライドする
⑤ ④の中で、引数strで受け取った文字列の文字数をreturnする
⑥ 実行用のクラス名も特に指定なしなので、仮にex10とする
⑦ ⑥において、Mainメソッドを定義する
⑧ ⑦の中で、Dragonクラスのインスタンスを生成する
⑨ ⑧を用いてCountメソッドに適当な文字列を与えた結果をConsole.WriteLineすることで動作確認

作成例

//p.274 練習問題
using System;
interface Countable { //インターフェイスの定義
    int Count(string str); //抽象メソッド
}
class Dragon : Countable { //インターフェイスを実装したクラスの定義
    public int Count(string x) { //抽象メソッドのオーバライド
        return x.Length;
    }
}
class ex10 { //実行用クラス
    public static void Main() {
        Dragon y = new Dragon(); //インターフェイスを実装したクラスのオブジェクト生成
        Console.WriteLine("aの文字数は{0}です", y.Count("Happy!!"));
    }
}

今週の話題

今回トップは「ユニコーンオーバーロード(Switch)」GO!
【決算】ANYCOLORの3Q、2割の増収増益―コマース・ファンクラブ利用者は約120万人へ GO!
松竹とBrave groupがゲームメタバース事業で協業―『フォートナイト』内にオリジナルワールド制作、リアル連動イベントも GO!
「Snowflake」活用でパフォーマンス向上とコストダウンを同時に達成―『FF7 EC』開発のアプリボットがデータ分析基盤の構築事例を紹介【CAGC2024】GO!

オンラインゲームにおけるハラスメントの放置はビジネス的損失をもたらす―米団体が無料レポート公開 GO!

講義メモ 後半

p.263 複数のインターフェイスを実装する

・1クラスで複数のクラスを継承することはできない
・1クラスで複数のインターフェイスを実装することは可能
・書式: class クラス名 : インターフェイス名①, インターフェイス名②, … {…}
・実装した全てのインターフェイスの抽象メンバのオーバライドが求められる
・例:
interface Flyable { string HowToFly(); } //飛行体を示すインターフェイス
interface Runable { string HowToRun(); } //走行体を示すインターフェイス
class Dragon : Flyable, Runable {
  public string HowToFly() { return "腕力で飛ぶ"; }
  public string HowToRun() { return "脚力で走る"; }
}

p.263 interface04.cs 正誤

・010行目「interface ISecond : IFirst」→「interface ISecond」

p.263 interface04.cs

//p.263 interface04.cs
using System;
interface IFirst { //インターフェイス①の定義
    void show(int x); //抽象メソッド①
}
interface ISecond { //インターフェイス②の定義
    void show(int x, int y); //抽象メソッド②
}
class MyClass : IFirst, ISecond { //インターフェイス①と②を実装するクラス
    public void show(int x) { //抽象メソッド①のオーバライド
        Console.WriteLine("x = {0}", x);
    }
    public void show(int x, int y) { //抽象メソッド②のオーバライドでオーバーロードになる
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}
class interface04 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.show(2); //抽象メソッド①のオーバライドを呼ぶ
        mc.show(1, 3); //抽象メソッド②のオーバライドを呼ぶ
    }
}

p.263 (複数の同じシグニチャのメソッドを持つインターフェイスを実装する)

・1クラスで複数のインターフェイスを実装する時、そこに同じシグニチャのメソッドがあると1つのオーバライドで両方に当てはまり、
 エラーにはならない
 ※テキストでは「明示して実装する必要がある」となっているがエラーになるわけではない

アレンジ演習:p.263 interface04.cs

・「void show(int x, int y); //抽象メソッド②」を「void show(int y); //抽象メソッド②」としても、同じ動作をすることを
 確認せよ

作成例

//アレンジ演習:p.263 interface04.cs
using System;
interface IFirst { //インターフェイス①の定義
    void show(int x); //抽象メソッド①
}
interface ISecond { //インターフェイス②の定義
    void show(int y); //抽象メソッド② ※①と同じシグニチャ
}
class MyClass : IFirst, ISecond { //インターフェイス①と②を実装するクラス
    public void show(int x) { //抽象メソッド①のオーバライド兼②のオーバライド
        Console.WriteLine("x = {0}", x);
    }
    public void show(int x, int y) { //オーバライドではなく自前のメソッドでオーバーロードになる
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}
class interface04 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.show(2); //抽象メソッド①②のオーバライドを呼ぶ
        mc.show(1, 3); //オーバーロードを呼ぶ
    }
}

p.263 (複数の同じシグニチャのメソッドを持つインターフェイスを実装する):続き

・1クラスで複数のインターフェイスを実装する時、そこに同じシグニチャのメソッドがあると1つのオーバライドで両方に当てはまり、
 どちらのインターフェイスを型とする変数を経由しても実行される

アレンジ演習:p.263 interface04.cs 続き

・MyClassの変数をインターフェイス①型に代入して抽象メソッド①のオーバライドを呼ぶ
・MyClassの変数をインターフェイス②型に代入して抽象メソッド②のオーバライドを呼ぶ
・どちらも動作をすることを確認せよ

作成例

//アレンジ演習:p.263 interface04.cs
using System;
interface IFirst { //インターフェイス①の定義
    void show(int x); //抽象メソッド①
}
interface ISecond { //インターフェイス②の定義
    void show(int y); //抽象メソッド② ※①と同じシグニチャ
}
class MyClass : IFirst, ISecond { //インターフェイス①と②を実装するクラス
    public void show(int x) { //抽象メソッド①のオーバライド兼②のオーバライド
        Console.WriteLine("x = {0}", x);
    }
    public void show(int x, int y) { //オーバライドではなく自前のメソッドでオーバーロードになる
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}
class interface04 {
    public static void Main() {
        MyClass mc = new MyClass();
        IFirst ifi = mc; //インターフェイス①型に代入
        ifi.show(2); //抽象メソッド①のオーバライドを呼ぶ
        ISecond ise = mc; //インターフェイス②型に代入
        ise.show(1); //抽象メソッド②のオーバライドを呼ぶ
    }
}

p.263 (複数の同じシグニチャのメソッドを持つインターフェイスを実装する):続き=テキストp.264

・1クラスで複数のインターフェイスを実装する時、そこに同じシグニチャのメソッドがあるときに、これを区別してオーバライドしたい
 場合は「インターフェイス名.」を前置すると良い
・これを行ったメソッドは自動的にpublicになり、publicを指定するとエラーになるので注意

アレンジ演習:p.263 interface04.cs 続き

・抽象メソッド①のオーバライド兼②のオーバライドである「public void show(int x)」を区別してオーバライドして
 動作を確認しよう
・「public void show(int x, int y)」は削除して良い

作成例

//アレンジ演習:p.263 interface04.cs
using System;
interface IFirst { //インターフェイス①の定義
    void show(int x); //抽象メソッド①
}
interface ISecond { //インターフェイス②の定義
    void show(int y); //抽象メソッド② ※①と同じシグニチャ
}
class MyClass : IFirst, ISecond { //インターフェイス①と②を実装するクラス
    void IFirst.show(int x) { //抽象メソッド①のオーバライド
        Console.WriteLine("IFirst = {0}", x);
    }
    void ISecond.show(int x) { //抽象メソッド②のオーバライド
        Console.WriteLine("ISecond = {0}", x);
    }
}
class interface04 {
    public static void Main() {
        MyClass mc = new MyClass();
        IFirst ifi = mc; //インターフェイス①型に代入
        ifi.show(1); //抽象メソッド①のオーバライドを呼ぶ
        ISecond ise = mc; //インターフェイス②型に代入
        ise.show(2); //抽象メソッド②のオーバライドを呼ぶ
    }
}

p.264 interface05.csについて

・005行目の「public」は不要
・010行目の「public」は不要

p.265 interface05.cs

//p.265 interface05.cs
using System;
interface IMas { //「です・ます」を示すインターフェイス①
    void show(int i); //抽象メソッド①
}
interface IDa { //「だ・である」を示すインターフェイス②
    void show(int i); //抽象メソッド② ※①と同じシグニチャ
}
class MyClass : IMas, IDa { //上記2インターフェイスを実装するクラス
    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); //抽象メソッド②のオーバライドを実行
    }
}

【補足】クラスの継承とインターフェイスの実装

・クラスの継承とインターフェイスの実装は同時に行うことができる
・ただし、基本クラスをインターフェイスよりも前に記述すること
・書式例: class 派生クラス名 : 基本クラス名, インターフェイス名①, インターフェイス名② {…}
・なお、抽象クラスの継承とインターフェイスの実装を同時に行うこともできる
・この時、同じシグニチャの抽象メソッドを持つインターフェイスを実装することも可能

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

・抽象クラスの継承とインターフェイスの実装を同時に行うこともできることを確認しよう

作成例

//アレンジ演習:p.265 interface05.cs
using System;
interface IMas { //「です・ます」を示すインターフェイス①
    void show(int i); //抽象メソッド①
}
interface IDa { //「だ・である」を示すインターフェイス②
    void show(int i); //抽象メソッド② ※①と同じシグニチャ
}
abstract class Base { //【追加】抽象クラス
    public abstract void show(int i); //抽象メソッド③
}
class MyClass : Base, IMas, IDa { //【変更】抽象クラスを継承し2インターフェイスを実装するクラス
    void IMas.show(int i) { //抽象メソッド①のオーバライドなので「です・ます」
        Console.WriteLine("iは{0}です", i);
    }
    void IDa.show(int i) { //抽象メソッド②のオーバライドなので「だ・である」
        Console.WriteLine("iは{0}だ", i);
    }
    public override void 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); //抽象メソッド②のオーバライドを実行
        mc.show(5); //【追加】インターフェイス型の変数を経由しないと抽象メソッド③のオーバライドを実行
    }
}

提出:ミニ演習 mini266.cs

・「アレンジ演習:p.265 interface05.cs」からIDaインターフェイスを除外して、動作を確認しよう

講義メモ

・p.255「インターフェイスとは」から

提出フォロー:アレンジ演習:p.250 partial01.cs

・MyClassクラスの定義②を、別ファイル(partial02.cs)としてソース分割しよう

作成例:partial01.cs(分割元)

//アレンジ演習:p.250 partial01.cs
using System;
partial class MyClass { //MyClassクラスの定義①
    public int x;
}
class partial01 { //partial01クラスの定義
    public static void Main() {
        MyClass mc = new MyClass();
        mc.x = 10;
        mc.Show();
    }
}

作成例:partial02.cs(分割先)

using System; //自動作成される
partial class MyClass { //MyClassクラスの定義②
    public void Show() {
        Console.WriteLine("x = {0}", x);
    }
}

第10章 インターフェイス

p.255 インターフェイスとは

・インターフェイスの元の意味は「異なる要素を関連付ける仕組み」「接合面」
・C#では「継承関係のないクラスを関連付けられる仕組み」
・例えば、画面上にドラゴンと戦闘機が飛び交うゲームにおいて、ドラゴンクラスと戦闘機クラスが継承関係になることは考えづらい。
 しかし、双方のクラスが「飛行体」インターフェイスを持てば(実装すれば)、飛行体に含まれるものとしてまとめて扱える
・このように、クラスに基本クラスを定義する形に似た書式で、クラスにインターフェイスを実装できる

p.255 インターフェイスの宣言

・インターフェイスは抽象クラスに似た形で定義し、クラスを徹底的に抽象化したものになる
・具体的には、抽象メソッド、抽象プロパティ、抽象インデクサのみを持つことができるのがインターフェイス
・抽象クラスとは異なり、1つのクラスで複数のインターフェイスを実装できる(クラスの継承は1つのみ)
・これは例えば「飛行体でもあり、走行体でもあるマシン」の場合
・インターフェイスの定義書式: interface インターフェイス名 {…}
・抽象メソッドの定義書式: 戻り値型 メソッド名(引数リスト);
・抽象プロパティの定義書式: 戻り値型 プロパティ名 { get; set; } ※getとsetのどちらかは省略可
・抽象インデクサの定義書式: 戻り値型 this(インデックス型 インデックス);
・インターフェイスの定義例: interface Flyable { string HowToFly(); } //飛行体を示すインターフェイス

p.256 インターフェイスの実装

・クラスの継承と同じ書式で、インターフェイスの実装が可能
・例: class Dragon : Flyable {…}
・クラスの継承とは異なり、複数のインターフェイスの実装が可能
・例: class Dragon : Flyable, Swimable {…}
・抽象クラスの継承と同様に、インターフェイスを実装したクラスでは抽象メンバのオーバライドによる具象(具体化)が求められる
・この時、overrideキーワードは不要だが、publicメソッドにすること
・例: class Dragon : Flyable { public string HowToFly() { return "翼で飛ぶ"; } }
・クラスを利用する側から見ると、インターフェイスを実装しているクラスではインターフェイスがそのクラスの性質を表すことになり、
 メリットが大きい

p.257 interface01.cs

//p.257 interface01.cs
using System;
interface IMyInterface { //インターフェイスの定義
    void show(string str); //抽象メソッド
    int xprop { get; set; } //抽象プロパティ
    int this[int i] { get; set; } //抽象インデクサ
}
class MyClass : IMyInterface { //インターフェイスを実装するクラス
    int i; //非公開のデータメンバ ※「protected」は不要
    int[] arr = new int[10]; //非公開の配列
    public void show(string str) { //抽象メソッドのオーバライド(具象化)
        Console.WriteLine(str);
    }
    public int xprop { //抽象プロパティのオーバライド(具象化)
        get { return i; } set { i = value; }
    }
    public int this[int index] { //抽象インデクサのオーバライド(具象化)
        get { return arr[index]; } set { arr[index] = value; }
    }       
}
class interface01 {
    public static void Main() {
        MyClass mc = new MyClass(); //インターフェイスを実装したクラス
        mc.show("Test Interface"); //抽象メソッドのオーバライド(set)を呼ぶ
        mc.xprop = 100; //抽象プロパティのオーバライド(set)を呼ぶ
        Console.WriteLine("mc.xprop = {0}", mc.xprop); //抽象メソッドのオーバライド(get)を呼ぶ
        for (int i = 0; i < 10; i++) {
            mc[i] = i * 2; //抽象インデクサのオーバライド(set)を呼ぶ
        }
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("mc[{0}] = {1}", i, mc[i]); //抽象インデクサのオーバライド(get)を呼ぶ
        }        
    }
}

p.259 1つのインターフェイスを複数のクラスで実装する

・継承関係のない複数のクラスを、同じインターフェイスを実装するクラスとして、関連付けることができる
・同じインターフェイスを実装しているクラスであれば、同じ抽象メンバのオーバライドがあることが保証されることがポイント

p.259 interface02.cs

//p.259 interface02.cs
using System;
interface IMyInterface { //インターフェイスの定義
    void show(string str); //抽象メソッド
}
class MyClass : IMyInterface { //インターフェイスを実装するクラス①
    public void show(string s) { //抽象メソッドのオーバライド①
        Console.WriteLine(s);
    }
}
class YourClass : IMyInterface { //インターフェイスを実装するクラス②
    public void show(string x) { //抽象メソッドのオーバライド②
        Console.WriteLine("{0}が入力されました", x);
    }
}
class interface02 {
    public static void Main() {
        MyClass mc = new MyClass();
        YourClass yc = new YourClass();
        mc.show("abc"); //抽象メソッドのオーバライド①を呼ぶ
        yc.show("abc"); //抽象メソッドのオーバライド②を呼ぶ
    }
}

p.260(インターフェイスを型とする参照変数)

・抽象クラスのインスタンスは生成できないのと同様に、インターフェイスのインスタンスは生成できない
・抽象クラスを型とする参照変数が定義できるのとと同様に、インターフェイスを型とする参照変数を定義できる
・抽象クラスAを継承する派生クラスBのインスタンスは、Aを型として扱うことができる
・同様に、インターフェイスCを実装するクラスDのインスタンスは、Cを型として扱うことができる
・例: 飛べるものであるドラゴンの「ヴェルドラ」は、飛べるものの「ヴェルドラ」である
 inteface Flyable {}
 class Dragon : Flyable {}
 class Test { void Play() { Dragon Veldra = new Dragon(); Flyable flyone = Veldra; }
・なお、インターフェイスを型とする配列も定義でき、要素として、インターフェイスを実装するクラスのインスタンスを格納できる
・例: 飛べるものであるドラゴンの「ヴェルドラ」は、飛べるもの配列の[0]である

p.261 interface03.cs

//p.261 interface03.cs
using System;
interface IMyInterface { //インターフェイスの定義
    int calc(int x, int y); //抽象メソッド
}
class Plus : IMyInterface { //インターフェイスを実装するクラス①
    public int calc(int a, int b) { //抽象メソッドのオーバライド①「計算せよ」は加算とする
        return a + b;
    }
}
class Minus : IMyInterface { //インターフェイスを実装するクラス②
    public int calc(int a, int b) { //抽象メソッドのオーバライド②「計算せよ」は減算とする
        return a - b;
    }
}
class interface03 {
    public static void Main() {
        IMyInterface im; //インターフェイスを型とする参照変数
        Plus p = new Plus();
        Minus m = new Minus();
        im = p; //Plusクラスはインターフェイスを実装しているのでインターフェイスを型とする参照変数に代入可
        Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //抽象メソッドのオーバライドがあると保証される
        im = m; //Minusクラスはインターフェイスを実装しているのでインターフェイスを型とする参照変数に代入可
        Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //抽象メソッドのオーバライドがあると保証される
    }
}

アレンジ演習:p.261 interface03.cs

・インターフェイスの定義を下記に変更
  interface Flyable { string HowToFly(); } //飛行体を示すインターフェイス
・実装するクラスを下記に変更
  class Dragon : Flyable { public string HowToFly() { return "腕力で飛ぶ"; } }
  class F16 : Flyable { public string HowToFly() { return "ジェットで飛ぶ"; } }
・多態性が発揮されることを確認しよう

作成例

//アレンジ演習:p.261 interface03.cs
using System;
interface Flyable { string HowToFly(); } //飛行体を示すインターフェイス
class Dragon : Flyable { //インターフェイスを実装するクラス①
    public string HowToFly() { return "腕力で飛ぶ"; } //抽象メソッドのオーバライド①
}
class F16 : Flyable { //インターフェイスを実装するクラス②
    public string HowToFly() { return "ジェットで飛ぶ"; } //抽象メソッドのオーバライド②
}
class interface03 {
    public static void Main() {
        Flyable flyer; //インターフェイスを型とする参照変数
        Dragon Veldra = new Dragon();
        F16 Blue = new F16();
        flyer = Veldra; //Dragonクラスはインターフェイスを実装しているのでインターフェイスを型とする参照変数に代入可
        Console.WriteLine("flyer.HowToFly = {0}", flyer.HowToFly()); //抽象メソッドのオーバライドがあると保証される
        flyer = Blue; //F16クラスはインターフェイスを実装しているのでインターフェイスを型とする参照変数に代入可
        Console.WriteLine("flyer.HowToFly = {0}", flyer.HowToFly()); //抽象メソッドのオーバライドがあると保証される
    }
}

アレンジ演習:p.261 interface03.cs つづき

・Flyableインターフェイス型の配列に格納するようにしよう

作成例

//アレンジ演習:p.261 interface03.cs
using System;
interface Flyable { string HowToFly(); } //飛行体を示すインターフェイス
class Dragon : Flyable { //インターフェイスを実装するクラス①
    public string HowToFly() { return "腕力で飛ぶ"; } //抽象メソッドのオーバライド①
}
class F16 : Flyable { //インターフェイスを実装するクラス②
    public string HowToFly() { return "ジェットで飛ぶ"; } //抽象メソッドのオーバライド②
}
class interface03 {
    public static void Main() {
        Dragon Veldra = new Dragon();
        F16 Blue = new F16();
        Flyable[] flyers = { Veldra, Blue }; //上記をインターフェイスを型とする配列に格納
        foreach (var w in flyers) { //配列の全要素について繰返す
            Console.WriteLine(w.HowToFly()); //抽象メソッドのオーバライドがあると保証される
        }
    }
}

今週の話題

今回トップは「ファイナルファンタジーVII リバース(PS5)」GO!
学生がもっと“eスポーツ”に触れる機会を―ヒューマンアカデミーが学校にゲーミングデバイスを寄贈するプランを展開する狙い GO!
広井王子氏が考えるeスポーツとゲームの未来、そして映画との深い繋がりとは―eスポーツ映画「PLAY! ~勝つとか負けるとかは、どーでもよくて~」公開直前インタビュー! GO!
Unity、有償プランの値上げを日本でのみ実施―円安に伴う為替レート変更 個人向けの無料版であるUnity Personalに影響はありません GO!

セガサミーのゲーム事業は新作軟調、過度な広告費で営業利益が急減【ゲーム企業の決算を読む】GO!
従業員の発言切っ掛けに議論が過熱。ゲームへの多様性導入巡り開発コンサル企業に海外で是非の声 GO!
【決算】gumi、3Qの売上高3割減、営業損失30億円―『アスタタ』不調やブロックチェーンゲーム宣伝費が重く GO!

前回のコメント

・partialキーワードがとても便利だなと思いました

 確かに便利ですね。
 長いプログラムを書く時や、チーム開発で活用できますので、是非、使いこなしてください。

・抽象クラスを使いこなせるようになりたい

 継承とインターフェイスの理解につがりますので、これも、是非、使いこなしてください。