class Base { } class Sub : Base { }
class Base { public void Method1() { } public virtual void Method2() { } public virtual void Method3() { } } class Sub : Base { public void Method1() { } // CS0108 'Sub.Method1()' は継承されたメンバー 'Base.Method1()' を非表示にします。非表示にする場合は、キーワード new を使用してください。 public void Method2() { } // CS0114 'Sub.Method2()' は継承されたメンバー 'Base.Method2()' を非表示にします。現在のメンバーでその実装をオーバーライドするには、override キーワードを追加してください。オーバーライドしない場合は、new キーワードを追加してください。 public override void Method3() { } // OK }
class Base1 { public abstract void Method1(); // CS0513 'Base1.Method1()' は抽象ですが、非抽象クラスの 'Base1' に含まれています。 } abstract class Base2 { public abstract void Method1() { } // CS0500 'Base2.Method1()' は abstract に指定されているため本体を宣言できません。 public abstract void Method2(); // OK } class Sub : Base2 // CS0534 'Sub' は継承抽象メンバー 'Base2.Method1()' を実装しません。 { public void Method1() { } // CS0114 'Sub.Method1()' は継承されたメンバー 'Base2.Method1()' を非表示にします。現在のメンバーでその実装をオーバーライドするには、override キーワードを追加してください。オーバーライドしない場合は、new キーワードを追加してください。 public override void Method2() { } // OK }
virtualやabstractで宣言されているメンバを、拡張して実装します。
abstract class Base1 { public void Method1() { } public virtual void Method2() { } public abstract void Method3(); } class Sub : Base1 { public override void Method0() { } // CS0115 'Sub.Method0()': オーバーライドする適切なメソッドが見つかりませんでした。 public override void Method1() { } // CS0506 'Sub.Method1()': 継承されたメンバー 'Base1.Method1()' は virtual、abstract または override に設定されていないためオーバーライドできません。 public override void Method2() { } // OK public override void Method3() { } // OK }
派生クラス (derived class) から、オーバーライドした基本クラス (base class / 基底クラス) のメンバを呼び出せます。base キーワード - C# リファレンス | Microsoft Learn
public override void Method2() { base.Method2(); }
class Base1 { protected virtual void Method1() { } protected virtual void Method2() { } protected virtual void Method3() { } protected virtual void Method4() { } } class Sub : Base1 { public override void Method1() { } // CS0507 'Sub.Method1()': 'protected' の継承メンバー 'Base1.Method1()' をオーバーライドするときに、アクセス修飾子を変更できません。 public new void Method2() { } // OK protected override void Method3() { } // OK protected new void Method4() { } // OK }
派生クラスでnewで非表示にしたメンバの、アクセス修飾子を変更する場合を考えます。
class Base1 { public void Method1() { Console.Write("Base"); } public void Method2() { Console.Write("Base"); } private void Method3() { Console.Write("Base"); } private void Method4() { Console.Write("Base"); } } class Sub : Base1 { public new void Method1() { Console.Write("Sub"); } private new void Method2() { Console.Write("Sub"); } public new void Method3() { Console.Write("Sub"); } // warning CS0109: メンバー 'Sub.Method3()' は継承されたメンバーを非表示にしません。new キーワードは不要です。 private new void Method4() { Console.Write("Sub"); } // warning CS0109: メンバー 'Sub.Method4()' は継承されたメンバーを非表示にしません。new キーワードは不要です。 public void Func() { Method1(); // Sub Method2(); // Sub … 派生クラスのメンバへアクセス可能なため、それが呼ばれる Method3(); // Sub Method4(); // Sub } }
派生クラスのインスタンスから呼ぶ場合は、アクセス可能なメンバが呼ばれます。
Sub sub = new Sub(); sub.Method1(); // Sub sub.Method2(); // Base … 派生クラスのメンバはprivateなため、基本クラスのそれが呼ばれる sub.Method3(); // Sub sub.Method4(); // error CS0122: 'Sub.Method4()' はアクセスできない保護レベルになっています
基本クラスと、それを継承した派生クラスを定義して検証します。
class Base { public virtual void Method1() { Console.Write("Base"); } public virtual void Method2() { Console.Write("Base"); } } class Sub : Base { public override void Method1() { Console.Write("Sub"); } public new void Method2() { Console.Write("Sub"); } }
次の3通りの場合について、それぞれ呼ばれるメソッドを確認します。
// 1 Base c1 = new Base(); c1.Method1(); // Base … 基本クラスのメソッドが呼ばれる c1.Method2(); // Base … 同上 // 2 Sub c2 = new Sub(); c2.Method1(); // Sub … 派生クラスのメソッドが呼ばれる c2.Method2(); // Sub … 同上 // 3 Base c3 = new Sub(); c3.Method1(); // Sub … overrideで拡張されていると、派生クラスのメソッドが呼ばれる c3.Method2(); // Base … newで隠蔽されていると、基本クラスのメソッドが呼ばれる
class C1 { public virtual void M1() { Console.Write("C1"); } public virtual void M2() { Console.Write("C1"); } public virtual void M3() { Console.Write("C1"); } } class C2 : C1 { public override void M1() { Console.Write("C2"); } public override void M2() { Console.Write("C2"); } public new void M3() { Console.Write("C2"); } } class C3 : C2 { public override void M1() { Console.Write("C3"); } public new void M2() { Console.Write("C3"); } public new void M3() { Console.Write("C3"); } }
C3 c3 = new C3(); ((C1)c3).M1(); // C3 ((C1)c3).M2(); // C2 ((C1)c3).M3(); // C1 … C2.M3()がnewで隠蔽されているため ((C2)c3).M1(); // C3 ((C2)c3).M2(); // C2 … C3.M2()がnewで隠蔽されているため ((C2)c3).M3(); // C2 … C3.M3()がnewで隠蔽されているため c3.M1(); // C3 c3.M2(); // C3 c3.M3(); // C3
newで隠蔽されていると、呼び出し元の型のメソッドが呼ばれます。