講義メモ(最終回) ・p.259「1つのインターフェイスを複数のクラスで実装する」から 提出フォロー:アレンジ演習:p.257 interface01.cs ・IMyInterfaceインターフェイスを実装するYourClassを追加し、MainメソッドでMyClassと同様に扱えることを試そう 作成例 //アレンジ演習: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; 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 YourClass : IMyInterface { //【以下追加】インターフェイスを実装したクラス② ※上記と同一内容 int i; 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"); //抽象メソッドのオーバーライド①を呼ぶ 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)のオーバーライド①を呼ぶ } //【以下追加】上記のクラス名、変数名を替えたもので同一内容 YourClass md = new YourClass(); //インターフェイスを実装したクラス②のインスタンスを生成 md.show("Test Interface 2"); //抽象メソッドのオーバーライド②を呼ぶ md.xprop = 100; //抽象プロパティ(set)のオーバーライド②を呼ぶ Console.WriteLine("md.xprop = {0}", md.xprop); //抽象プロパティ(get)のオーバーライド②を呼ぶ for (int i = 0; i < 10; i++) { md[i] = i * 2; //抽象インデクサ(set)のオーバーライド②を呼ぶ } for (int i = 0; i < 10; i++) { Console.WriteLine("md[{0}] = {1}", i, md[i]); //抽象インデクサ(get)のオーバーライド②を呼ぶ } } } p.259 1つのインターフェイスを複数のクラスで実装する ・1つのインターフェイスを複数のクラスで実装でき、抽象メンバ(メソッド、プロパティ、インデクサ)をそれぞれにおいてオーバーライドする アレンジ演習 p.257 interface02.cs ・IMyInterfaceインターフェイスに、以下の抽象プロパティを追加し、各クラスでオーバーライドしよう int xprop { get; set; } ・オーバーライドの内容は自由 作成例 //アレンジ演習 p.257 interface02.cs using System; interface IMyInterface { //インターフェイスの定義 void show(string str); //抽象メソッド int xprop { get; set; } //【追加】抽象プロパティ } class MyClass : IMyInterface { //インターフェイスを実装するクラス① int x; //【追加】 public void show(string s) { Console.WriteLine(s); } public int xprop { //【追加】抽象プロパティのオーバーライド① get { return x; } set { x = value; } } } class YourClass : IMyInterface { //インターフェイスを実装するクラス② int y; //【追加】 public void show(string x) { Console.WriteLine("{0}が入力されました", x); } public int xprop { //【追加】抽象プロパティのオーバーライド② get { return y; } set { y = value; } } } class interface02 { public static void Main() { MyClass mc = new MyClass(); // インターフェイスを実装するクラス①から生成 YourClass yc = new YourClass(); // インターフェイスを実装するクラス②から生成 mc.show("abc"); //①でオーバーライドしているメソッドを呼ぶ yc.show("abc"); //②でオーバーライドしているメソッドを呼ぶ //【以下追加】 mc.xprop = 10; //①でオーバーライドしているプロパティのsetを呼ぶ Console.WriteLine(mc.xprop); //①でオーバーライドしているプロパティのgetを呼ぶ yc.xprop = 30; //②でオーバーライドしているプロパティのsetを呼ぶ Console.WriteLine(yc.xprop); //②でオーバーライドしているプロパティのgetを呼ぶ } } p.260 1つのインターフェイスを複数のクラスで実装する:インターフェイスを型とする参照変数 ・インターフェイスも、抽象クラスもインスタンスを生成することはできない ・しかし、インターフェイスや、抽象クラスを型とする参照変数は宣言できる ・この参照変数に、インターフェイスを実装するオブジェクトや、派生クラスのオブジェクトを代入することで、参照をコピーすることができる ・よって、インターフェイスを実装する複数のクラスに対して、オーバーライドしているメンバを同じ形式で呼び出すことができる アレンジ演習:p.261 interface03.cs ・インターフェイスIMyInterfaceを型とする配列iaを生成しよう ・そして、変数p、mを格納して、配列の要素経由でCalcメソッドを実行してみよう 作成例 //アレンジ演習: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; //インターフェイスを型とする参照変数にクラス①のオブジェクトを代入 Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //参照変数経由でメソッド①を実行 im = m; //インターフェイスを型とする参照変数にクラス②のオブジェクトを代入 Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //参照変数経由でメソッド①を実行 //【以下追加】インターフェイスを型とする配列に上記を格納 IMyInterface[] ia = {p, m}; foreach (var i in ia) { //全要素について繰返す Console.WriteLine("i[].calc = {0}", i.calc(3, 5)); // } } } p.263 複数のインターフェイスを実装する ・クラスが複数のクラスを継承することはできない ・しかし、複数のインターフェイスを実装することはできる p.263【正誤】interface04.cs ・010行:「: IFirst」はインターフェイスの継承にあたるが、ここでは不要 アレンジ演習:p.263 interface04.cs ・IFirstインターフェースのみを実装するYourClassを追加し、Show(int)メソッドを適当にオーバーライドする ・YourClassのオブジェクトycを生成し、IFirstインターフェースを型とする配列に、mcと共に格納できるか確認しよう 作成例 //アレンジ演習: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 YourClass : IFirst { //【以下追加】インターフェース①のみを実装するクラス② public void show(int x) { //抽象メソッド①のオーバーライド Console.WriteLine("x = {0}", x); } } class interface04 { public static void Main() { MyClass mc = new MyClass(); mc.show(2); //抽象メソッド①のオーバーライドを呼ぶ mc.show(1, 3); //抽象メソッド②のオーバーライドを呼ぶ //【以下追加】 YourClass yc = new YourClass(); IFirst[] ifa = {mc, yc}; //インターフェイス①を型とする配列に格納 foreach (var w in ifa) { //この配列の全要素について繰返す w.show(100); //抽象メソッド①のオーバーライドを呼ぶ } } } p.263 複数のインターフェイスを実装する:同じシグニチャのメソッドが含まれている場合 ・同じシグニチャのメソッドが含まれている場合、その両方をオーバーライドする必要がある ・そこで、識別するために「戻り値型 インターフェイス名.メソッド名(){…}」として記述する ・この時、publicは不要(記述するとエラーになる) ・呼び出す側では、インターフェイス型の参照変数を用いることで、どちらかを識別できる p.264【正誤】interface05.cs ・005行:「public」は不要 ・010行:「public」は不要 アレンジ演習:p.264 interface05.cs ・インターフェイス型の参照変数を用いずに「mc.Show(5);」と呼び出すとどうなるか確認しよう 作成例 //p.264 interface05.cs using System; interface IMas { //インターフェイス① void show(int i); //抽象メソッド① } 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); //インターフェイス②の抽象メソッド②のオーバーライドが実行 //mc.show(5); //文法エラーになる } } p.266 インターフェイスの継承 ・クラスと同様にインターフェイスが継承が可能 ・継承される側を基本インターフェイス、する側を派生インターフェイスと呼ぶ ・クラスと同様に継承できるインターフェイスは1つのみで、派生インターフェイスの継承は可能 アレンジ演習:p.266 interface06.cs ・派生インターフェイスIInterface2を継承するIInterface3を追加できることを確認しよう  ※中身は自由 作成例 //アレンジ演習: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(); //抽象メソッド④ } interface IInterface3 : IInterface2 { //【以下追加】派生の派生インターフェイス③ //ここに void setdatano(int n); //抽象メソッド①があるとみなされる //ここに void setdata(double data, int i); //抽象メソッド②があるとみなされる //ここに double calcsum(); //抽象メソッド③があるとみなされる //ここに double calcaverage(); //抽象メソッド④があるとみなされる double calcmax(); //抽象メソッド⑤ } class MyClass : IInterface3 { //【変更】派生の派生インターフェイス③を実装するクラス double[] data; bool bOK = false; //OKフラグ(false:準備前) 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; } public double calcsum() { //抽象メソッド③のオーバーライド if (!bOK) { //OKフラグが準備前? 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; //件数で割って平均値を得て返す } public double calcmax() { //【以下追加】抽象メソッド⑤のオーバーライド if (!bOK) { //OKフラグが準備前? Console.WriteLine("配列の準備ができていません"); return -1.0; //値を返す必要があるので、ダミーの値を返す } double max = -1.0; //最大値用(※仮に正の数限定とする) for (int i = 0; i < data.Length; i++) { //全要素について繰返す max = (max > data[i]) ? max : data[i]; //最大値を更新 } return max; //最大値を返す } } 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("最大 = {0}", mc.calcmax()); //【追加】 Console.WriteLine(); Console.Write("続けますか(Y/N)---"); string yn = Console.ReadLine(); if (yn == "N" || yn == "n") { break; } } } } p.270 インターフェイスの継承:同じシグニチャの抽象メンバがある場合 ・派生インターフェイスにおいて、基本インターフェイスと同じシグニチャの抽象メンバがある場合、名前の隠ぺいが起こる ・この場合、newキーワードを追記して、名前の隠ぺいであることを明示すると良い アレンジ演習:p.270 interface07.cs ・派生インターフェイスIMyInterface2を継承するIMyInterface3を追加しよう ・この中で、Show2()メソッドの名前の隠ぺいができることを試そう 作成例 //アレンジ演習:p.270 interface07.cs using System; interface IMyInterface { //基本インターフェイス① void show1(); //抽象メソッド① void show2(); //抽象メソッド② } interface IMyInterface2 : IMyInterface { //派生インターフェイス② //ここに「void show1(); //抽象メソッド①」があるとみなされるが隠ぺいされる new void show1(); //抽象メソッド①の名前の隠ぺい //ここに「void show2(); //抽象メソッド②」があるとみなされる void show3(); //抽象メソッド③ } interface IMyInterface3 : IMyInterface2 { //【以下追加】派生の派生インターフェイス③ //ここに「void show1(); //抽象メソッド①」があるとみなされるが隠ぺいされる //ここに「new void show1(); //抽象メソッド①の名前の隠ぺいがあるとみなされる //ここに「void show2(); //抽象メソッド②」があるとみなされるが隠ぺいされる new void show2(); //抽象メソッド②の名前の隠ぺい //ここに「void show3(); //抽象メソッド③」があるとみなされる } class MyClass : IMyInterface3 { //【変更】派生の派生インターフェイス③を実装するクラス 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.266 インターフェイスの継承:名前の隠ぺい時に隠ぺいされたメソッドをオーバーライドする ・複数のインターフェイスを実装する時に、同じシグニチャのメソッドが含まれている場合と同様に「インターフェイス名.メソッド名」と記述すれば、名前の隠ぺい時に隠ぺいされたメソッドをオーバーライドすることができる ・そして、利用時にインターフェイスを型とする参照変数を経由することで識別が可能 アレンジ演習:p.272 interface08.cs ・派生インターフェイスI2を継承するI3を追加しよう ・この中で、Show2()メソッドの名前の隠ぺいを行う ・MyClassクラスは派生の派生インターフェイスI3を実装するようにしよう 作成例 //アレンジ演習:p.272 interface08.cs using System; interface I1 { //基本インターフェイス① void show1(); //抽象メソッド① void show2(); //抽象メソッド② } interface I2 : I1 { //派生インターフェイス② new void show1(); //抽象メソッド①の名前の隠ぺい } interface I3 : I2 { //【追加】派生の派生インターフェイス③ new void show2(); //抽象メソッド②の名前の隠ぺい } class MyClass : I3 { //【変更】派生の派生インターフェイス②を実装するクラス void I1.show1() { //隠ぺいされた基本インターフェイス①の抽象メソッド①のオーバーライド Console.WriteLine("I1.show1"); } void I2.show1() { //隠ぺいした派生インターフェイス②の抽象メソッド①のオーバーライド Console.WriteLine("I2.show1"); } void I1.show2() { //【変更】基本インターフェイス①の抽象メソッド②のオーバーライド Console.WriteLine("I1.show2"); } void I3.show2() { //【追加】隠ぺいした派生の派生インターフェイス③の抽象メソッド②のオーバーライド Console.WriteLine("I3.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(); //派生インターフェイス②の抽象メソッド②のオーバーライドを呼ぶ事も可能 //【以下追加】 I3 i3; //派生の派生インターフェイス③を型とする参照変数 i3 = mc; //派生の派生インターフェイス②を型とする参照変数を経由することで i3.show2(); //派生の派生インターフェイス③の抽象メソッド②のオーバーライドを呼ぶ事も可能 } } p.274 練習問題 ex1001.cs ヒント ・インターフェイス名を MyInterface とする ・これを実装するクラスを MyClass とする ・文字数を返すには「return str.Length;」で良い ・ex1001クラスにMainメソッドをおいて、MyClassのオブジェクトを生成してCountメソッドを試せば良い 作成例 //p.274 練習問題 ex1001.cs using System; interface MyInterface { //インターフェイス int Count(string str); //抽象メソッド } class MyClass : MyInterface { //インターフェイスを実装するクラス public int Count(string str) { //抽象メソッドのオーバーライド return str.Length; //引数で受け取った文字列の文字数を返す } } class ex1001 { public static void Main() { MyClass mc = new MyClass(); //インターフェイスを実装するクラスのオブジェクトを生成 Console.WriteLine(mc.Count("Hello")); //抽象メソッドのオーバーライドを呼ぶ } } 以上