メソッドのオーバーロード(継承関係)

オーバーロードは、メソッド名が同じで引数の型が異なる場合、同じクラスに記述することができる機能になります。
この応用として、UnityEngineのクラスの一つでComponentクラスととの派生クラスについてみていきましょう。
引数の型における継承の優先順位を確認することが目的です。

チュートリアル

プロジェクトの作成

新規で3Dプロジェクトを作成します。

オブジェクトの配置

追加で、次のオブジェクトを作成します。

  • 空のゲームオブジェクト
  • Cube

スクリプト

空のゲームオブジェクトに次のスクリプトをアタッチします。

Inheritance.cs

using UnityEngine;

public class Inheritance : MonoBehaviour
{
    [SerializeField]
    Transform tran;

    [SerializeField]
    Collider col;

    void Start()
    {
        TransParam(tran);
        TransParam(col);
    }

    void TransParam(Component component)
    {
        Debug.Log("引数が、Component型");
    }

    void TransParam(Transform trans)
    {
        Debug.Log("引数が、Transform型");
    }
}

インスペクターで、次のアウトセット接続をします。

  • tranに、Cube
  • colにも、Cube

同じ、CubeオブジェクトをD&Dしますが、それぞれ宣言された型がTransformとColliderであるため、

  • tranには、CubeオブジェクトのTransformコンポーネントの参照
  • colには、CubeオブジェクトのColliderコンポーネントの参照

が、それぞれ、代入されます。
次にStartメソッドで、2つのTransParamメソッドが実行されますが、それぞれの引数の型が違いますね。

void Start()
{
    TransParam(tran);
    TransParam(col);
}

Transform型の引数を持つメソッドは、次のようになります。

void TransParam(Transform trans)
{
    Debug.Log("引数が、Transform型");
}

これは、TransParam(tran)メソッドによって呼び出されますね。

では、TransPram(col)の方はどうでしょうか?
もう一つのメソッドは型の引数にComponent型を持ちますが、Collider型の引数ではありません。
Collider型の引数を持つメソッドが存在しないのでエラーになるでしょうか?

そうはなりません。
Collider型は、Component型を基本クラスに持つ派生クラスです。

public class Collider : Component
{
    // Colliderのメンバー群
}

この場合、Collider型の引数を持つメソッドは存在しないのですが、その基本クラスの型を持つメソッドが見つかると、そちらが実行されることになるのです。

試してみましょう

Transform型を引数に持つメソッド本体をコメントアウトして実行してみましょう。
どのような結果になりますか?エラーになりますか?
結果から、わかることを考えてみましょう

もっと他のサンプルは?

では、次のケースは、どうでしょうか?
何をしているコードでしょうか?・・・

そうです。配列の合計を計算しているのですね。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Interface : MonoBehaviour
{
    void Start()
    {
        int[] scoresArray = { 70, 30, 50 };
        Sum(scoresArray);
    }

    void Sum(int[] scores)
    {
        int sum = 0;

        foreach (var score in scores)
        {
            sum += score;
        }
        Debug.Log(sum);
    }
}

では、リストだとどんな感じでしょうか?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Interface : MonoBehaviour
{
    void Start()
    {
        List<int> scoresList = new List<int> { 70, 30, 50 };
        Sum(scoresList);
    }

    void Sum(List<int> scores)
    {
        int sum = 0;

        foreach (var score in scores)
        {
            sum += score;
        }
        Debug.Log(sum);
    }
}

ですね。配列とリストを扱うには、メソッドのオーバーロードを利用して次のようになるでしょう

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Interface : MonoBehaviour
{
    void Start()
    {
        int[] scoresArray = { 70, 30, 50 };
        Sum(scoresArray);

        List<int> scoresList = new List<int> { 70, 30, 50 };
        Sum(scoresList);
    }

    void Sum(int[] scores)
    {
        int sum = 0;

        foreach (var score in scores)
        {
            sum += score;
        }
        Debug.Log(sum);
    }

    void Sum(List<int> scores)
    {
        int sum = 0;

        foreach (var score in scores)
        {
            sum += score;
        }
        Debug.Log(sum);
    }
}

でも、なんだか似通ってますね。

実は、引数の型の関係について、継承をみてきましたが、インターフェースについても同じものを実装している場合、実行することができるのです。
今回の場合は、配列とリストは共にIEnumerableインターフェースを実装していることを利用しています。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Interface : MonoBehaviour
{
    void Start()
    {
        int[] scoresArray = { 70, 30, 50 };
        Sum(scoresArray);

        List<int> scoresList = new List<int> { 70, 30, 50 };
        Sum(scoresList);
    }

    void Sum(IEnumerable<int> scores)
    {
        int sum = 0;

        foreach (var score in scores)
        {
            sum += score;
        }
        Debug.Log(sum);
    }
}

C#

Posted by hidepon