ラベル C# の投稿を表示しています。 すべての投稿を表示
ラベル C# の投稿を表示しています。 すべての投稿を表示

2011年10月24日月曜日

オーバーライド時のアクセス修飾子変更 C# 編

PHP 編Java 編に続き、 C# でも検証。C# は慣れていないため、怪しいかも・・・

まず、親クラス。
class ParentClass
{
  // 仮想または抽象メンバーには、private を指定できません。
  private /* virtual */ void func1() { Console.WriteLine("Parent private func1"); }
  protected virtual void func2() { Console.WriteLine("Parent protected func2"); }
  public virtual void func3() { Console.WriteLine("Parent public func3"); }

  public virtual void call()
  {
    this.func1();
    this.func2();
    this.func3();
  }
}

private, protected, public の 3 種類のメソッドと、それらを呼び出すメソッドを作成。
他と違い、この時点でエラーが発生。仮想関数を private にできないらしい。

子クラス1 は public に変更。
class Child1Class : ParentClass
{
  // オーバーライドする適切なメソッドが見つかりませんでした。
  public /* override */ void func1() { Console.WriteLine("Child1 private -> public func1"); }
  // 'protected' 継承メンバー 'ConsoleApplication1.ParentClass.func2()' をオーバーライドするときに、アクセス修飾子を変更できません。
  public /* override */ new void func2() { Console.WriteLine("Child1 protected -> public func2"); }
  public override void func3() { Console.WriteLine("Child1 public func3"); }
}

func1 は親クラスを virtual 宣言していないためオーバーライド出来ず、コンパイルエラーとなる。
func2 はアクセス修飾子が変更できない旨のエラーがでる。PHP や Java と違い緩い方向にも変更できない。
func1, func2 共に override を外すと、コンパイルは通る。
func2 は override を外しただけでは、override か new を付けろと警告が出る。

子クラス2 は protected に変更。
class Child2Class : ParentClass
{
  // オーバーライドする適切なメソッドが見つかりませんでした。
  protected /* override */ void func1() { Console.WriteLine("Child2 private -> protected func1"); }
  protected override void func2() { Console.WriteLine("Child2 protected func2"); }
  // 'public' 継承メンバー 'ConsoleApplication1.ParentClass.func3()' をオーバーライドするときに、アクセス修飾子を変更できません。
  protected /* override */ new void func3() { Console.WriteLine("Child2 public -> protected func3"); }
}

func1 は同じようにエラー。
func3 はアクセス修飾子の変更によるエラー。

子クラス3 は private に変更。
class Child3Class : ParentClass
{
  // 仮想または抽象メンバーには、private を指定できません。
  private /* override */ void func1() { Console.WriteLine("Child3 private func1"); }
  // 仮想または抽象メンバーには、private を指定できません。
  private /* override */ new void func2() { Console.WriteLine("Child3 protected -> private func2"); }
  // 仮想または抽象メンバーには、private を指定できません。
  private /* override */ new void func3() { Console.WriteLine("Child3 public -> private func3"); }
}

func1 は同じようにエラー。
func2, func3 もアクセス修飾子によるエラーとなる。

実行してみると、
ParentClass p = new ParentClass();
p.call();
Console.WriteLine("----------");
Child1Class c1 = new Child1Class();
c1.call();
Console.WriteLine("----------");
Child2Class c2 = new Child2Class();
c2.call();
Console.WriteLine("----------");
Child3Class c3 = new Child3Class();
c3.call();

結果は、
Parent private func1
Parent protected func2
Parent public func3
----------
Parent private func1
Parent protected func2
Child1 public func3
----------
Parent private func1
Child2 protected func2
Parent public func3
----------
Parent private func1
Parent protected func2
Parent public func3

ほとんどオーバーライド出来ないため、PHP や Java とは異なる結果になった。

private, public -> protected -> private 方向は勿論、protected -> public の変更もできないようだ。