学習記事一覧 · ターン制OOP入門


tags: [C#入門, Unity, オブジェクト指向]

【C# 入門】virtual と override で「上書き」を使いこなす — 継承の核心を車クラスで理解する

「親クラスのメソッドって、子クラスで書き直せるの?」— その答えが virtual と override です。Unity の MonoBehaviour を使っていれば、実は毎日使っている仕組みです。

まず「継承」をおさらい

C# では、あるクラスを元に別のクラスを作ることができます。これを 継承 と呼びます。

今回の例では Car(車)クラスを親とし、SportCar(スポーツカー)クラスが継承します。

Car と SportCar の継承関係

コードを読む前に:3つのキーワード

キーワード 内容
KEYWORD 01 abstract クラスを「設計図専用」にする。new で直接インスタンス化できない。
KEYWORD 02 virtual 「子クラスで上書きしてもいいよ」という許可マーク。
KEYWORD 03 override 子クラスが親の virtual メソッドを実際に上書きするときに付ける。
BONUS base.メソッド() 上書きした後でも、親の処理を呼び出したいときに使う。

親クラス Car を作る

abstract を付けると、このクラスは「直接 new Car() できない設計図」になります。

// abstract クラスは new Car() できない「設計図」
public abstract class Car
{
    // virtual をつけると子クラスで override(上書き)可能
    public virtual void Run()
    {
        Debug.Log("走るよ!");
    }
    // virtual がないので子クラスで上書きできない
    public void Stop()
    {
        Debug.Log("止まるよ");
    }
}

📌 ポイント: Stop() には virtual がありません。これは「この処理は子クラスで変えなくていい」という設計上の意図です。

子クラス SportCar で Run() を上書きする

public class SportCar : Car  // Car クラスを継承
{
    public override void Run()  // Run() を上書き
    {
        Debug.Log("超速く走るよ!");
        base.Run();  // 親の Run() も呼ぶ →「走るよ!」も出力
    }
}

📌 base.Run() とは? 「上書きした上で、親の処理も実行したい」ときに使います。base は「親クラス」を指します。省略すると親の Run() は呼ばれません。

実際に動かしてみる

Unity で動かすには、MonoBehaviour を継承したスクリプトを作り、空の GameObject にアタッチします。

using UnityEngine;
public class CarTest : MonoBehaviour
{
    void Start()
    {
        SportCar sportCar = new SportCar();
        sportCar.Run();   // SportCar の Run() が呼ばれる
        sportCar.Stop();  // Car の Stop() がそのまま使われる
    }
}

手順

  1. Car.csSportCar.csCarTest.cs の3ファイルを Assets に作成
  2. 空の GameObject を作成し、CarTest をアタッチ
  3. Play ボタンを押すと Console に出力される

Console 出力:

超速く走るよ!
走るよ!
止まるよ

⚠️ なぜ「超速く走るよ!」の後に「走るよ!」が出るの? base.Run() を書いているため、上書きした処理の後に親の処理も実行されます。base.Run() を消すと「超速く走るよ!」だけになります。

virtual と override の対応関係を整理

キーワード どこに書く 意味
virtual 親クラスのメソッド 「子クラスで上書きしてよい」と宣言する
override 子クラスのメソッド 親の virtual メソッドを実際に上書きする
base.〇〇() override したメソッド内 上書きしつつ親の処理も呼び出す
abstract クラス or メソッド 直接インスタンス化・実装を禁止し、継承を強制する

Unity との繋がり:実は毎日使っている

MonoBehaviour の Start() や Update() を使ったことがありますよね?

あれはまさに Unity が用意した virtual メソッドを、あなたが override している仕組みです(Unity では省略記法が使われていますが、内部は同じです)。

public class MyScript : MonoBehaviour
{
    // MonoBehaviour の virtual void Start() を override している
    void Start() { }
    // MonoBehaviour の virtual void Update() を override している
    void Update() { }
}

📌 つまり: virtual / override を理解することは、Unity の動作原理を理解することに直結しています。


まとめ

virtual は「上書きしてもいいよ」という親からの許可。override は子クラスがその許可を使って実際に上書きすること。base.メソッド() で親の処理も併用できる。abstract はクラスを設計図専用にして直接 new できなくする仕組みです。

この4つを押さえると、複数の車種(Truck、Busなど)を同じ Car 型で扱いつつ、Run() の挙動だけ個別に変える — いわゆる ポリモーフィズム の入口まで、一気に見えてきます。