オーバーライドのおさらい (C++/C#/Javaの比較)

見た目がよく似た3つの言語で微妙に挙動が異なるのでまとめ。

C++の場合

#include <stdio.h>

class BaseClass {
public:
  void hoge() { printf("BaseClass::hoge\n"); }
  virtual void piyo() { printf("BaseClass::piyo\n"); } // 仮想関数
};

class SubClass : public BaseClass {
public:
  void hoge() { printf("SubClass::hoge\n"); }
  void piyo() override { printf("SubClass::piyo\n"); } // 仮想関数のオーバーライド
};

int main(void) {
  BaseClass base;
  base.hoge();
  base.piyo();

  SubClass sub;
  sub.hoge();
  sub.piyo();

  BaseClass *x = new SubClass();
  x->hoge();  // BaseClass::hoge
  x->piyo();  // SubClass::piyo
  return 0;
}

【実行結果】

BaseClass::hoge
BaseClass::piyo
SubClass::hoge
SubClass::piyo
BaseClass::hoge
SubClass::piyo

override指定子は付けても付けなくても同じだが、仮想関数でない関数にoverride指定子を付けるとエラーになる。ミスを防ぐために付けた方がよい。

C#の場合

using System;

class BaseClass
{
  public void hoge() { Console.WriteLine("BaseClass.hoge"); }
  public virtual void piyo() { Console.WriteLine("BaseClass.piyo"); } // 仮想メソッド
  public virtual void fuga() { Console.WriteLine("BaseClass.fuga"); } // 仮想メソッド
}

class SubClass : BaseClass
{
  public void hoge() { Console.WriteLine("SubClass.hoge"); }
  public override void piyo() { Console.WriteLine("SubClass.piyo"); } // overide指定子を付ける
  public void fuga() { Console.WriteLine("SubClass.fuga"); } // overide指定子を付けない
}

class Program
{
  public static void Main(string[] args)
  {
    BaseClass baseObj = new BaseClass();
    baseObj.hoge();
    baseObj.piyo();
    baseObj.fuga();

    SubClass subObj = new SubClass();
    subObj.hoge();
    subObj.piyo();
    subObj.fuga();

    BaseClass x = new SubClass();
    x.hoge();  // BaseClass.hoge
    x.piyo();  // SubClass.piyo
    x.fuga();  // BaseClass.fuga
  }
}

【実行結果】

BaseClass.hoge
BaseClass.piyo
BaseClass.fuga
SubClass.hoge
SubClass.piyo
SubClass.fuga
BaseClass.hoge
SubClass.piyo
BaseClass.fuga

C#の場合、仮想メソッドであっても overide指定子を付けないと通常のメソッドと同じような挙動になる。これを明示的に宣言するにはoveride指定子のかわりにnew指定子を付ける。

Javaの場合

class BaseClass {
  public void hoge() { System.out.println("BaseClass.hoge"); }
}

class SubClass extends BaseClass {
  @Override
  public void hoge() { System.out.println("SubClass.hoge"); }
}

class Main {
  public static void main(String[] args) {
    BaseClass baseObj = new BaseClass();
    baseObj.hoge();

    SubClass subObj = new SubClass();
    subObj.hoge();

    BaseClass x = new SubClass();
    x.hoge(); // SubClass.hoge
  }
}

【実行結果】

BaseClass.hoge
SubClass.hoge
SubClass.hoge

Javaの場合、publicなメソッドは常に仮想メソッドとなる。@Overrideアノテーションは付けても付けなくても同じだが、オーバーライドしていない場合 (基底クラスに同名のメソッドが無いなどの場合) はエラーになる。ミスを防ぐために付けた方がよい。