WisdomSoft - for your serial experiences.

継承と型変換

派生クラスのオブジェクトを基本クラス型に変換する暗黙の参照変換と、基本クラスのオブジェクトを派生クラス型に変換する明示的な参照変換について解説します。継承関係にあるクラスのオブジェクトは変換することができ、中でも無条件に派生クラスのオブジェクトを基本クラス型として扱える事を理解することは、コードの抽象化とオブジェクト指向の本質を理解するために必要不可欠です。

暗黙の参照変換

継承は、基本クラスの機能を派生クラスで拡張するというものでした。派生クラスは基本クラスのメンバを持つため、派生クラスのオブジェクトは基本クラスのオブジェクトと同等の機能を提供します。従って、派生クラス型のオブジェクトは、安全に基本クラス型のオブジェクトとして扱えます。基本クラス型のオブジェクトとして操作しても、何も矛盾はありません。

派生クラス型のインスタンスへの参照を、基本クラス型のインスタンスの参照と扱っても、コード上ではオブジェクトの振る舞いに違いはありません。そのため、派生クラス型から基本クラス型へは暗黙的に変換できます。これを暗黙の参照変換(implicit reference conversion)と呼びます。

class A {}
class B : A {}
class C : A {}

例えば、上記のような A クラス帆基本クラスとする B クラスと C クラスの 2 つの派生クラスが宣言されているとき、B クラス型と C クラス型のオブジェクトは、暗黙的に A クラス型に変換できます。一方、B クラスと C クラスには直接の継承関係はないため、これらを互いに変換することはできません。

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

objA = objB; //OK
objA = objC; //OK
objB = objC; //Error

派生クラスを基本クラスとして扱える暗黙の参照変換を応用することで、コードの再利用や組み換えが容易になります。

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

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


class Test
{
    public static void Main(string[] args)
    {
        PrettyCure curePeace = new PrettyCure();
        curePeace.Name = "黄瀬やよい";
        curePeace.CureName = "キュアピース";

        MagicalGirl magicalGirl = curePeace;
        System.Console.WriteLine("MagicalGirl Name=" + magicalGirl.Name);

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

コード1の PrettyCure クラスは MagicalGirl クラスから派生しています。Main() メソッド内で PrettyCure クラスのインスタンスを PrettyCure 型の curePeace 変数に代入しています。この変数は PrettyCure 型なので PrettyCure クラスのすべての機能にアクセスできます。

PrettyCure 型の curePeace 変数を、基本クラス型である MagicalGirl 型の magicalGirl 変数に代入しています。これらの変数は型が異なりますが、MagicalGirl クラスは PrettyCure クラスの基本クラスなので暗黙の参照変換によって代入可能です。magicalGirl 変数に代入された参照は、実際の型が PrettyCure クラスのインスタンスでも、MagicalGirl 型の機能にしかアクセスできません。従って curePeace 変数からは Name プロパティと CureName プロパティの両方を使えますが、magicalGirl 変数は Name プロパティしか使えません。

また、暗黙的な参照変換で基本型に変換されても、インスタンスそのものが変換されるわけではありません。表面上の変数の型(インスタンスが持つメンバ)が基本クラス型に制限されるというだけで、インスタンスの実際の型は変換されません。

明示的な参照変換

暗黙の参照変換は派生クラス型から基本クラス型に変換するものでしたが、これとは逆の変換は暗黙的に行うことはできません。暗黙の参照変換によって基本クラス型に変換されたオブジェクトは、表面上の変数の型は基本クラス型でも、インスタンスの実際の型は派生クラス型です。このような場合、キャスト式を用いて基本クラス型のオブジェクトを派生クラス型のオブジェクトに変換できます。このような、基本クラス型から派生クラス型への変換を明示的な参照変換(explicit reference conversions.)と呼びます。

A objA = new B();
B objB = (B)objA; //OK
C objC = (C)objA; //Runtime error

上記のコードで B クラスと C クラスが A クラスの派生クラスである場合、A クラス型の変数に変換された B クラス型のオブジェクトはキャスト式で B クラス型に変換できます。

一方 objA 変数に格納されているオブジェクトの実際の型が B クラスなので、これを継承関係のない C クラスに変換しようとした場合、B クラス C クラスに型の互換性がないため実行時エラーとなります。シャスと式による変換は、構文上は問題ないためコンパイルは可能です。

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

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


class Test
{
    public static void Main(string[] args)
    {
        MagicalGirl magicalGirl = new PrettyCure();
        magicalGirl.Name = "黄瀬やよい";
        System.Console.WriteLine("MagicalGirl Name=" + magicalGirl.Name);

        PrettyCure curePeace = (PrettyCure)magicalGirl;
        curePeace.CureName = "キュアピース";
        System.Console.WriteLine("PrettyCure Name=" + curePeace.Name);
        System.Console.WriteLine("PrettyCure CureName=" + curePeace.CureName);
    }
}
実行結果
コード2 実行結果

コード2コード1とは逆に、最初に PrettyCure オブジェクトを MagicalGirl 型の magicalGirl 変数に代入し、その後、キャスト式を用いた明示的な参照変換で PrettyCure 型の curePeace 変数に代入しています。magicalGirl 変数が参照しているインスタンスは PrettyCure 型なので、このキャスト式は安全に行えます。しかし、もし magicalGirl 変数が PrettyCure クラス以外のインスタンスを参照している場合はエラーが発生するので注意してください。