p.255 インターフェイスとは
・元の意味は「異なる要素を関連付けるための仕組み」「接合口」「接合面」など ・C#などのオブジェクト指向言語では「継承関係のないクラスを関連付けるための仕組み」 ・例えば「飛べるもの」インタフェースを持つドラゴンクラスと飛行機クラスを記述し、これらのオブジェクトを「飛べるもの」として 扱える
p.255 インターフェイスの宣言
・書式: interface インターフェイス名 {…}
・インタフェースには抽象メソッド、抽象プロパティ、抽象インデクサを記述できる
※ Java等とは異なり、データメンバh記述できない
・よって、抽象クラスをより徹底したものになっている
・インターフェイス内の抽象メンバでは「abstract」指定は不用(「virtual」も不要)
・抽象プロパティ、抽象インデクサはget、setの内容を記述しないもの
・インターフェイスの抽象プロパティの書式: 型 プロパティ名 { get; set; }
・インターフェイスの抽象インデクサの書式: 型 this[インデックスの型 インデックス] { get; set; }
・どちらも、getまたはsetを省略できる(通常、setを省略して書き換え不可に)
p.256 インターフェイスの実装
・クラスにおける継承を、インターフェイスでは実装という
・1クラスは1クラスしか継承できないが、1クラスが複数のインターフェイスを実装できる
・書式: class クラス名 : インターフェイス名,… {…}
例: class Dragon : Flyable, Swimable {…} //ドラゴンは飛べる&泳げる
・抽象クラスを継承した派生クラスと同様に、抽象メソッドをもつインターフェイスを実装したクラスは、抽象メソッドをオーバーライド
する必要があるが、overrideキーワードは不要で、publicにすること。
p.257 3行目 正誤
【誤】インターフェイスを実装するメソッドは必ずpublicとなります。 【正】インターフェイスの抽象メンバをオーバーライドするメンバは必ずpublicとなります。
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 { //インターフェイスを実装するクラス
protected int i; //※このprotectedは特に意味はない
int[] arr = new int[10]; //インデクサ用
public void show(string str) { //抽象メソッドのオーバーライド(override不用)
Console.WriteLine(str);
}
public int xprop { //抽象プロパティのオーバーライド(override不用)
get { return i; }
set { i = value; }
}
public int this[int index] { //抽象インデクサのオーバーライド(override不用)
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を呼ぶ
}
}
}
p.258 下7行 正誤
・4つある「仮想」はすべて「抽象」の誤り 【誤】インターフェイスの実装メンバがすべてpublic 【正】インターフェイスの抽象メンバをオーバーライドするメンバがすべてpublic ※ インターフェイスの抽象メンバをオーバーライドすることを「実装する」という場合もある
p.359 1つのインターフェイスを複数のクラスで実装する
・1つのインターフェイスを複数のクラスで実装することが可能 ・こうすることで、継承関係のない複数のクラスをインターフェイスによって関連付けることができる
p.261 interface02.cs
//p.261 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」と扱える ・例: 飛べるインターフェイスを実装する飛行機クラスのオブジェクト「B787」を「飛べるもの B」と扱える
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; //インターフェイスを実装するクラスのオブジェクトは、インターフェイスを型とする参照変数で扱える
Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //抽象メソッドのオーバーライド①を呼ぶ
im = m; //同上
Console.WriteLine("im.calc = {0}", im.calc(3, 5)); //抽象メソッドのオーバーライド②を呼ぶ
}
}
アレンジ演習: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 = { new Plus(), new Minus() };
foreach (var w in im) { //配列の全要素について繰返す
Console.WriteLine("im.calc = {0}", w.calc(3, 5)); //抽象メソッドのオーバーライドを呼ぶ
}
}
}
p.263 複数のインターフェイスを実装する
・1クラスは1クラスしか継承できないが、1クラスが複数のインターフェイスを実装できる
・書式: class クラス名 : インターフェイス名,… {…}
p.263 interface04.cs 010行目 正誤
【誤】interface ISecond : IFirst 【正】interface ISecond ※ インターフェイスの継承(p.266)になっているが、このプログラムでは不要 ※ エラーにはならないが、MyClassで2つのインターフェイスを実装する意味がなくなってしまう
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.264 複数のインターフェイスを実装する(同じシグニチャの場合)
・複数の同じシグニチャの抽象メンバをもつインターフェイスを実装することができる
・この場合、インターフェイスを型とする参照変数を定義して用いると良い
・書式: インターフェイスを型とする参照変数.メソッド名(引数)
例:
interface 空中を飛べる { void 飛び方(); }
interface 宇宙を飛べる { void 飛び方(); }
class スペースドラゴン : 空中を飛べる, 宇宙を飛べる {
空中を飛べる 空中用; //インターフェイスを型とする参照変数①を定義
宇宙を飛べる 宇宙用; //インターフェイスを型とする参照変数②を定義
public void 空中用.飛び方() { Console.Write("火を噴きながら飛ぶ"); } //参照変数①を利用
public void 宇宙用.飛び方() { Console.Write("静かに飛ぶ"); } //参照変数②を利用
}
提出:アレンジ演習:p.261 interface03.cs