WisdomSoft - for your serial experiences.

メンバの隠ぺい

継承した派生クラスで基本クラスと同じシグネチャのメンバを宣言した場合、基本クラスのメンバが派生クラスによって隠ぺいされます。

基本クラスと同じメンバを宣言する

基本クラスで宣言されているメンバと同じメンバを、派生クラスで宣言することができます。この場合でもエラーになることはなく、単に派生クラスで宣言されたメンバが基本クラスから継承した同名のメンバを隠します。派生クラスで基本クラスと同じシグネチャのメンバを宣言することを、基本クラスのメンバを隠ぺいする(hide the base class member)と呼びます。

基本クラスのメンバを隠ぺいした場合、メンバの実体が 1 つに収束するわけではなく、基本クラスと派生クラスで同じメンバが重複して存在するようになります。

class A
{
    public int Value { get; set; }
}

class B : A
{
    public int Value { get; set; }
}

上記のコードでは A クラスの Value プロパティと、A クラスから派生する B クラスの Value プロパティが同じ名前です。よって B クラスで A クラスのValue プロパティを隠ぺいしています。この場合 B クラスのインスタンスは A クラスで宣言された Value プロパティと B クラスで宣言された Value プロパティの両方を持ちます。

B クラスのオブジェクトから Value プロパティにアクセスした場合、オブジェクトの型によって、どちらの Value プロパティを利用するかが決定されます。A 型の変数であれば A クラスの Value プロパティが、B クラス(または B クラスから派生する型)の変数であれば B クラスの Value プロパティと解釈されます。

B objB = new B();
A objA = objB;

objA.Value = 10;
objB.Value = 100;
System.Console.WriteLine("A Value=" + objA.Value); //10
System.Console.WriteLine("B Value=" + objB.Value); //100

上のコードは B クラスのインスタンスを生成し、これを B 型の objB 変数と A 型の objA 変数から参照しています。このとき objA 変数から参照した Value プロパティは A クラスで宣言された Value プロパティを表し、objB 変数から参照した Value プロパティは B クラスで宣言された Value プロパティとなります。それぞれ、異なるプロパティとして機能します。

コード1
class MagicalGirl
{
    public string Name { get; set; }
}

class PrettyCure : MagicalGirl
{
    public string Name { get; set; }
}

class Test
{
    public static void Main(string[] args)
    {
        PrettyCure curePeace = new PrettyCure();
        curePeace.Name = "黄瀬やよい";

        MagicalGirl magicalGirl = curePeace;
        magicalGirl.Name = "キュアピース";

        System.Console.WriteLine("MagicalGirl Name=" + magicalGirl.Name);
        System.Console.WriteLine("PrettyCure Name=" + curePeace.Name);
    }
}
実行結果
コード1 実行結果

コード1の PrettyCure クラスは MagicalGirl クラスを継承し、基本クラスで宣言されている Name プロパティを隠ぺいしています。PrettyCure クラスのインスタンスを参照する変数の型によって、どちらの Name プロパティにアクセスするかが決定されます。PrettyCure 型の curePeace 変数から参照した場合は PrettyCure クラスの Name プロパティに、MagicalGirl 型の magicalGirl 変数から参照した場合は MagicalGirl クラスの Name プロパティにアクセスします。

上のような基本クラスのメンバを隠ぺいするコードをコンパイルすると図1のような警告が発生します。この警告は、偶然(開発者が意図せず)同じ名前のメンバを宣言してしまった可能性があるためです。

図1 メンバを隠ぺいする警告
図1 メンバを隠ぺいする警告

この警告を発生させないようにするには、明示的にメンバを隠ぺいします。明示的にメンバを隠ぺいするには new 修飾子(new modifier)でメンバ宣言を修飾します。

class A
{
    public int Value { get; set; }
}

class B : A
{
    public new int Value { get; set; }
}

この new 修飾子は public 修飾子と同じ、メンバ宣言を修飾する修飾子の一種なので、メンバの型よりも前に記述します。同じ修飾子である public 修飾子との順番は無関係ですが、一般には public などのアクセス修飾子を先に書きます。

コード2
class MagicalGirl
{
    public string Name { get; set; }
}

class PrettyCure : MagicalGirl
{
    public new string Name { get; set; }
}

class Test
{
    public static void Main(string[] args)
    {
        PrettyCure curePeace = new PrettyCure();
        curePeace.Name = "黄瀬やよい";

        MagicalGirl magicalGirl = curePeace;
        magicalGirl.Name = "キュアピース";

        System.Console.WriteLine("MagicalGirl Name=" + magicalGirl.Name);
        System.Console.WriteLine("PrettyCure Name=" + curePeace.Name);
    }
}
実行結果
コード2 実行結果

コード2の実行結果はコード1と同じです。PrettyCure クラスで基本クラスのメンバを隠ぺいするため Name プロパティの宣言に new 修飾子を追加しています。これによって、警告が発生しなくなります。

また new 修飾子が指定されているメンバが基本クラスのメンバを隠ぺいしない場合、エラーにはなりませんがコンパイラは警告を発生させます。