・p.229(baseキーワード)から
アレンジ演習:p.228 inheritance03.cs
・基本クラスの両メンバをprotectedにしても、名前の隠ぺいが起こること(同じ結果になること)を確認しよう
作成例
//アレンジ演習:p.228 inheritance03.cs
using System;
class Base { //基本クラス
protected int x = 10; //非公開だが継承可能なデータメンバ
protected void BaseMethod() { //非公開だが継承可能なメソッド
Console.WriteLine("Baseクラスです");
}
}
class Derived : Base { //派生クラス
new public int x = 20; //データメンバの名前の隠ぺい
new public void BaseMethod() { //メソッドの名前の隠ぺい
Console.WriteLine("Derivedクラスです");
}
}
class inheritance03 {
public static void Main() {
Derived d = new Derived(); //派生クラスのインスタンスを生成
Console.WriteLine("x = {0}", d.x); //隠ぺいしたデータメンバが用いられる
d.BaseMethod(); //隠ぺいしたメソッドが実行される
}
}
p.229(baseキーワード)
・名前の隠ぺいは基本クラスと同じ意味のメンバに同じ名前をつけることで、似た名前のメンバの乱立を防ぐことができる ・とはいえ「上書き」ではなく「隠ぺい」なので、対象となっている基本クラスのメンバを「base.」を前置することで呼び出し可能
p.229 inheritance04.cs
//p.229 inheritance04.cs
using System;
class Base { //基本クラス
protected int x = 10; //非公開だが継承可能なデータメンバ
}
class Derived : Base { //派生クラス
//ここに「protected int x = 10;」が継承されているが↓に隠ぺいされる
new int x = 20; //名前の隠ぺいを行うデータメンバ
public void Show() {
Console.WriteLine("base.x = {0}, x = {1} ", base.x, x); //隠ぺいされたxと隠ぺいしたxを表示
}
}
class inheritance04 {
public static void Main() {
Derived d = new Derived();
d.Show();
}
}
p.230 メソッドのオーバーライド
・メソッドにおける名前の隠ぺいの上位バージョンであり、後述の多態性を実現する
・よって、メソッドにおいては名前の隠ぺいではなく、オーバーライドを用いることが多い
・名前の隠ぺいとは異なり、基本クラス側の許可が必要であり、オーバーライドを可能とするメソッドは仮想メソッドにすること
・書式: public/protected virtual 戻り値型 メソッド名(引数リスト){内容}
・派生クラスでオーバーライドを行うメソッドはオーバライドメソッドにすること
・書式: アクセス修飾子 override 戻り値型 メソッド名(引数リスト){内容}
・なお、シグニチャとアクセス修飾子は仮想メソッドに合わせること
・静的メソッドは名前の隠ぺいは可能だが、オーバーライドは不可
p.231 override01.cs
//p.231 override01.cs
using System;
class MyBase { //基本クラス
public virtual void Method() { //オーバーライドを可能とする仮想メソッド
Console.WriteLine("MyBase");
}
}
class Derived1 : MyBase { //派生クラス①
public override void Method() { //オーバーライドメソッド①
Console.WriteLine("Derived1");
}
}
class Derived2 : MyBase { //派生クラス②
public override void Method() { //オーバーライドメソッド②
Console.WriteLine("Derived2");
}
}
class override01 {
public static void Main(){
Derived1 d1 = new Derived1();
Derived2 d2 = new Derived2();
d1.Method(); //オーバーライドメソッド①
d2.Method(); //オーバーライドメソッド②
}
}
p.232(多態性の前に、継承と参照変数)
・派生クラスのインスタンスは基本クラスの参照変数で扱うことができる
・これは「ホイミスライムのホイミンは、スライムとして扱える」ことと同じ。
例:
class Slime {}
class HoimiSlime : Slime {}
HoimiSlime hoimin = new HoimiSlime(); //ホイミスライムのホイミン
Slime shoimin = hoimin; //スライムのSホイミンとして扱える
・このことを利用すると、複数の派生クラスのオブジェクトを基本クラスのオブジェクトと一緒にして、基本クラスを型としてまとめて扱える
例: Slime[] slimes = {suralin, hoimin, behoimin}; //suralinはSlime型、
behoiminはHoimiSlimeを継承したBehoimiSlime型とする
p.232 多態性
・派生クラスのインスタンスを基本クラスの参照変数で扱うと、名前の隠ぺいの場合は、基本クラスのオブジェクトとして扱われる ・よって、派生クラスで独自に定義したメンバは利用できない ・これに対して、基本クラスの参照変数で扱っても、派生クラスの定義を用いるのが多態性 ・オーバーライドメソッドにおいては多態性が発生し、派生クラスのインスタンスを基本クラスの参照変数で扱っても、 オーバーライドメソッドがあれば、それが用いられる ・これにより、派生クラスのインスタンスを基本クラスの参照変数で扱う場合のデメリットを解消できる ・これにより、実際に実行されるメソッドの内容は、実行時に決まることになる(動的メソッドディスパッチという)
p.223 override02.cs
//p.223 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 { //派生クラス「猫」
//ここに「protected const int LegNo = 4;」があるとみなす
//ここに「protected const string Koe;」があるとみなす
//ここに「public int Leg()」があるとみなす
public override string Nakigoe() { //仮想メソッドをオーバライド
Koe = "ニャー、ニャー";
return Koe; //猫の声を返す
}
}
class Dog : Mammal { //派生クラス「犬」
//ここに「protected const int LegNo = 4;」があるとみなす
//ここに「protected const string Koe;」があるとみなす
//ここに「public int Leg()」があるとみなす
public override string Nakigoe() { //仮想メソッドをオーバライド
Koe = "ワン、ワン";
return Koe; //犬の声を返す
}
}
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()); //多態性が発揮され犬の声を返す
}
}
p.235 プロパティのオーバーライド
・プロパティ(p.207)はメソッドと同様にオーバライドが可能
・基本クラス側のプロパティは仮想プロパティに、派生クラス側のプロパティはオーバーライドプロパティにする
・書式: public/protected virtual 戻り値型 プロパティ名 {内容}
・書式: アクセス修飾子 override 戻り値型 プロパティ名 {内容}
p.236 override03.cs
//p.236 override03.cs
using System;
class Mammal { //哺乳類クラス
protected const int LegNo = 4; //非公開で継承可能な定数「脚の数」
public virtual string Nakigoe { //仮想プロパティ
get { return "..."; } //getのみ
}
public int Leg() { //公開で継承可能な通常メソッド
return LegNo;
}
}
class Cat : Mammal { //派生クラス「猫」
public override string Nakigoe { //オーバライドプロパティ
get { return "ニャー、ニャー"; } //getのみ
}
}
class Dog : Mammal { //派生クラス「犬」
public override string Nakigoe { //オーバライドプロパティ
get { return "ワン、ワン"; } //getのみ
}
}
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); //多態性が発揮され犬の声を返す
}
}
p.237 インデクサのオーバーライド
・メソッドと同様
・基本クラス側のインデクサは仮想インデクサに、派生クラス側のインデクサはオーバーライドインデクサにする
・書式: public/protected virtual 戻り値型 this[インデックス型 インデクス] {内容}
・書式: アクセス修飾子 override 戻り値型 this[インデックス型 インデクス] {内容}
作成例
//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] { //仮想インデクサ
get { return "..."; } //getのみ
}
public int Leg() { //公開で継承可能な通常メソッド
return LegNo;
}
}
class Cat : Mammal { //派生クラス「猫」
//ここに「protected const int LegNo = 4;」があると見なされる
//ここに「protected string Tail, Gei, Food, Koe;」があると見なされる
//ここに「public int Leg()」があると見なされる
public override string this[string index] { //オーバーライドインデクサ(インデックスは文字列)
get {
switch (index) {
case "尾": Tail = "1本"; return Tail;
case "芸": Gei = "できない"; return Gei;
case "鳴き声": Koe = "ニャー、ニャー"; return Koe;
case "食べ物": Food = "キャットフード"; return Food;
default: return "";
}
}
}
}
class Dog : Mammal { //派生クラス「犬」
//ここに「protected const int LegNo = 4;」があると見なされる
//ここに「protected string Tail, Gei, Food, Koe;」があると見なされる
//ここに「public int Leg()」があると見なされる
public override string this[string index] { //オーバーライドインデクサ(インデックスは文字列)
get {
switch (index) {
case "尾": Tail = "1本"; return Tail;
case "芸": Gei = "できる"; return Gei;
case "鳴き声": Koe = "ワン、ワン"; return Koe;
case "食べ物": Food = "ドッグフード"; return Food;
default: return "";
}
}
}
}
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.Leg(), m["尾"], m["芸"], m["食べ物"]); //文字列をインデックスとしてオーバーライドインデクサを呼ぶ
m = dog;
Console.WriteLine("犬の脚は{0}本です。尾は{1}です。芸は{2}。食べ物は{3}。",
m.Leg(), m["尾"], m["芸"], m["食べ物"]); //文字列をインデックスとしてオーバーライドインデクサを呼ぶ
}
}
p.240 クラスの多層構造
・派生クラスを基本クラスとしてさらに派生することが可能 ・派生の派生クラスには、基本クラスのメンバに加えて派生クラスが独自に定義したメンバも継承される ・派生の派生クラスで派生クラスの独自メソッドをオーバライドでき、この場合、派生クラスのメソッドは仮想メソッドにすること ・派生の派生クラスで派生クラスのオーバーライドメソッドをオーバライドする場合、派生クラスのメソッドはオーバーライドメソッのままで良い
p.240 inheritance05.cs
//p.240 inheritance05.cs
using System;
class MyBase { //基本クラス
protected int x = 10; //非公開だが継承可能なデータメンバ
public virtual void show() { //仮想メソッド
Console.WriteLine("x = {0}", x);
}
}
class Derived1 : MyBase { //派生クラス
//ここに「protected int x = 10;」があると見なされる
protected int y = 20;
//ここに「public virtual void show()」があると見なされ①オーバーライドされる
}
class Derived2 : Derived1 { //派生の派生クラス
//ここに「protected int x = 10;」があると見なされる
//ここに「protected int y = 20;」があると見なされる
int z = 30;
public override void show() { //派生クラスが継承したメソッドをオーバーライド②
Console.WriteLine("z = {0}", z);
}
}
class inheritance05 {
public static void Main() {
MyBase mb;
Derived1 d1 = new Derived1();
Derived2 d2 = new Derived2();
mb = d1; //派生クラスの参照変数を基本クラスの参照変数に代入することで扱う
mb.show(); //多態性により①が実行
mb = d2; //派生クラスの参照変数を基本クラスの参照変数に代入することで扱う
mb.show(); //多態性により②が実行
}
}