オーバーライド
From Wikipedia, the free encyclopedia
オブジェクト指向プログラミングにおいてオーバーライド (override) とは、スーパークラスで定義されたメソッドをサブクラスで定義し直し、動作を上書き(変更)することである。
例えば、あるクラスBaseにメソッドprintがあり、あるクラスDerivedがクラスBaseを継承したとする。そのとき、クラスDerivedはクラスBaseにあるメソッドprintをオーバーライドすることにより、再定義することができる。これはオブジェクト指向プログラミングにおけるポリモーフィズム(多態性)を実現する際によく使われる。
通例、オーバーライドを可能とする条件として、メソッドの名前、引数の数と型の順序、そして戻り値の型が統一されている必要がある[注釈 1]。
メソッドのオーバーロード(多重定義、overload)と名前は似ているが、まったく異なる概念である。
Rubyのようにオーバーロードの概念がなく、引数の型や数の条件がなくメソッド名が同一なだけでオーバーライドが成立するプログラミング言語もある。
Java
Javaのインスタンスメソッドは仮想メソッドであり、派生クラスでオーバーライド可能である。インスタンスメソッドを非仮想にする手段はないが、finalキーワードを指定することでオーバーライドを禁止することはできる。
なお、Java SE 5から導入されたアノテーション@Overrideを用いることで、メソッドがオーバーライドされていることをコンパイラに知らせることができる(正しくオーバーライドされていない場合、コンパイルエラーとなる)。しかし、アノテーションの指定はオプションであり必須ではない。
// 基本クラス。
class Base {
// コンストラクター
Base() {
System.out.println("Base.Base()");
}
// インスタンスメソッド
void print() {
System.out.println("Base.print()");
}
// クラスメソッド
static void staticPrint() {
System.out.println("Base.staticPrint()");
}
}
// 派生クラス。
class Derived extends Base {
// コンストラクター
Derived() {
System.out.println("Derived.Derived()");
}
// スーパークラスのインスタンスメソッド print をオーバーライドしている。@Override の指定は必須ではないが推奨される。
@Override
void print() {
System.out.println("Derived.print()");
}
// スーパークラスのクラスメソッド staticPrint をオーバーライドすることはできない。隠蔽することになる。
static void staticPrint() {
System.out.println("Derived.staticPrint()");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("■ Baseインスタンスメソッドの呼び出し:");
Base base = new Base();
base.print();
System.out.println("■ Derivedインスタンスメソッドの呼び出し:");
Derived derived = new Derived();
derived.print();
System.out.println("■ Base型変数を経由したDerivedインスタンスメソッドのポリモーフィック呼び出し:");
Base derivedInBaseVariable = new Derived();
derivedInBaseVariable.print();
System.out.println("■ Baseクラスメソッドの呼び出し:");
Base.staticPrint();
System.out.println("■ Derivedクラスメソッドの呼び出し:");
Derived.staticPrint();
}
}
実行結果:
■ Baseインスタンスメソッドの呼び出し:
Base.Base()
Base.print()
■ Derivedインスタンスメソッドの呼び出し:
Base.Base()
Derived.Derived()
Derived.print()
■ Base型変数を経由したDerivedインスタンスメソッドのポリモーフィック呼び出し:
Base.Base()
Derived.Derived()
Derived.print()
■ Baseクラスメソッドの呼び出し:
Base.staticPrint()
■ Derivedクラスメソッドの呼び出し:
Derived.staticPrint()
C#
C#のオーバーライドの特徴として、以下が挙げられる。
- 仮想メソッドおよび抽象メソッドのオーバーライドの際に
overrideキーワードの指定が必要である。
- ただし、インターフェイスのメソッドを実装する場合は、
overrideの指定は不要 (不可) である。
- メソッドは既定では非仮想であり、
virtualを指定することでオーバーライド可能な仮想メソッドとなる。 - プロパティ、インデクサ、イベントも、
virtual修飾されている場合はメソッドと同様にオーバーライドの対象となる。 sealedキーワードを指定することでオーバーライドを禁止できる。
コードの例を示す。
// 抽象基本クラス。
abstract class Base {
// 既定では非仮想メソッド。
public void GoodMorning() { Console.WriteLine("Good morning, Base!"); }
// virtualを指定することで仮想メソッドとなる。
public virtual void Hello() { Console.WriteLine("Hello, Base!"); }
public virtual void Goodbye() { Console.WriteLine("Goodbye, Base!"); }
// 抽象メソッド(実装を持たない)。
public abstract void GoodNight();
}
// 派生クラス。
class Derived : Base {
// 非仮想メソッドはオーバーライドできない。
// 同名のメソッドで隠蔽する場合、newを指定する。
// (ここでは指定しないが、さらにvirtualを指定することで仮想メソッドとなる)
public new void GoodMorning() { Console.WriteLine("Good morning, Derived!"); }
// 仮想メソッドをオーバーライドする。
// overrideの指定が必須。
public override void Hello() { Console.WriteLine("Hello, Derived!"); }
// 仮想メソッドをオーバーライドする。
// overrideと共にsealedを指定することで、このクラスを継承した先ではオーバーライドが禁止される。
public override sealed void Goodbye() { Console.WriteLine("Goodbye, Derived!"); }
// 抽象メソッドをオーバーライドする。
// overrideの指定が必須。
public override void GoodNight() { Console.WriteLine("Good night, Derived!"); }
}
class DerivedDerived : Derived {
// 非仮想メソッドはオーバーライド不可。
//public override void GoodMorning() { Console.WriteLine("Good morning, DerivedDerived!"); }
public override void Hello() { Console.WriteLine("Hello, DerivedDerived!"); }
// sealedされたメソッドはオーバーライド不可。
//public override void Goodbye() { Console.WriteLine("Goodbye, DerivedDerived!"); }
public override void GoodNight() { Console.WriteLine("Good night, DerivedDerived!"); }
}