
オブジェクト指向プログラミングにおけるメソッドのオーバーライドは、サブクラスまたは子クラスが、そのスーパークラスまたは親クラスの 1 つによって既に提供されているメソッドの特定の実装を提供できるようにする言語機能です。仮想ネットワーク インターフェイス全体にデータ駆動型アルゴリズムで決定されたパラメーターを提供することに加えて、[1]特定の種類のポリモーフィズム(サブタイピング) も可能にします。サブクラスの実装は、親クラスのメソッドと同じ名前、同じパラメーターまたはシグネチャ、同じ戻り値の型を持つメソッドを提供することで、スーパークラスの実装をオーバーライド (置き換え) します。[2]実行されるメソッドのバージョンは、それを呼び出すために使用されるオブジェクトによって決まります。親クラスのオブジェクトを使用してメソッドを呼び出す場合は、親クラスのバージョンが実行されますが、サブクラスのオブジェクトを使用してメソッドを呼び出す場合は、子クラスのバージョンが実行されます。[3]これにより、メソッドのオーバーライドが不要になる可能性のあるフレームワークに依存する差分リレー分析に関連する問題を防ぐことができます。[4] [5]一部の言語では、プログラマーがメソッドのオーバーライドを防ぐことができます。
言語固有の例
エイダ
Ada はデフォルトでメソッドのオーバーライドを提供します。早期のエラー検出 (スペルミスなど) を優先するために、メソッドが実際にオーバーライドされるかどうかを指定できます。これはコンパイラによってチェックされます。
型 Tは、 新しいControlled with ......; procedure Op ( Obj : in out T ; Data : in Integer );です 。
型 NT は ヌルレコードを持つ新しいTです 。オーバーライドしています-- オーバーライド インジケータプロシージャOp ( Obj : in out NT ; Data : in Integer );オーバーライドしています-- オーバーライド インジケータプロシージャOp ( Obj : in out NT ; Data : in String ); -- ^ コンパイラがエラーを発行します: サブプログラム "Op" はオーバーライドされていません
C#
C# はメソッドのオーバーライドをサポートしますが、修飾子overrideandvirtualまたは を使用して明示的に要求された場合のみですabstract。
抽象クラスAnimal { public string Name { get ; set ; } // メソッドpublic void Drink (); public virtual void Eat (); public void Go (); }
class Cat : Animal { public new string Name { get ; set ; } // メソッドpublic void Drink (); // 警告: 継承された drink() を非表示にします。新しいpublic override void Eat ();を使用してください。 // 継承された eat() をオーバーライドします。public new void Go (); // 継承された go() を非表示にします。}
あるメソッドを別のメソッドでオーバーライドする場合、 2 つのメソッドのシグネチャは同一 (および同じ可視性) である必要があります。C# では、クラス メソッド、インデクサー、プロパティ、およびイベントはすべてオーバーライドできます。
非仮想メソッドまたは静的メソッドはオーバーライドできません。オーバーライドされる基本メソッドは、virtual、abstract、またはoverride である必要があります。
メソッドのオーバーライドに使用される修飾子に加えて、C# では継承されたプロパティやメソッドを非表示にnewすることができます。これは、プロパティやメソッドの同じシグネチャを使用し、その前に修飾子を追加することで行われます。 [6]
上記の例では、非表示にすると次のようになります。
猫cat =新しい猫();
cat . Name = … ; // Cat.Name にアクセスしますcat . Eat (); // Cat.Eat() を呼び出しますcat . Go (); // Cat.Go() を呼び出します(( Animal ) cat ). Name = … ; // Animal.Name! にアクセスします(( Animal ) cat ). Eat (); // Cat.Eat()! を呼び出します(( Animal ) cat ). Go (); // Animal.Go()! を呼び出します
C++
C++ にsuperは、サブクラスがオーバーライドしたいメソッドのスーパークラスバージョンを呼び出すために Java で使用できるキーワードがありません。代わりに、親または基底クラスの名前に続いてスコープ解決演算子を使用します。たとえば、次のコードでは、基底クラスと派生クラス の2 つのクラスが示されています。はクラスのメソッドをオーバーライドし、その高さも出力します。[7]RectangleBoxBoxRectanglePrint
#include <iostream>
//---------------------------------------------------------------------------
クラスRectangle { public : Rectangle ( double l , double w ) : length_ ( l ), width_ ( w ) {} virtual void Print () const ;
プライベート:
double length_ ; double width_ ; };
//---------------------------------------------------------------------------
void Rectangle::Print () const { // 基本クラスの印刷メソッド。std :: cout << "Length = " << length_ << "; Width = " << width_ ; }
//---------------------------------------------------------------------------
クラスBox : public Rectangle { public : Box ( double l , double w , double h ) : Rectangle ( l , w ), height_ ( h ) {} void Print () const override ;
プライベート:
double height_ ; };
//---------------------------------------------------------------------------
// 派生クラスの Print メソッド。
void Box::Print () const { // 親の Print メソッドを呼び出します。Rectangle :: Print (); std :: cout << "; Height = " << height_ ; }
Printクラス のメソッドはBox、 メソッド の親バージョンを呼び出すことにより、基本クラスのプライベート変数および をPrint出力することもできます。それ以外の場合、これらの変数は にアクセスできません。
lengthwidthBox
次のステートメントは、型と型のオブジェクトをインスタンス化し、それぞれのメソッドを呼び出します。
RectangleBoxPrint
int main ( int argc , char ** argv ) {四角形rectangle ( 5.0 , 3.0 );
// 出力: 長さ = 5.0; 幅 = 3.0
rectangle . Print ();
ボックスボックス( 6.0 、5.0 、4.0 );
// Box::print の vtable 内で最もオーバーライドされているメソッドへのポインターですが、
//この呼び出しはオーバーライドを示していません。box.Print ( );
// この呼び出しはオーバーライドを示しています。
// 出力: 長さ = 6.0; 幅 = 5.0; 高さ = 4.0 static_cast < Rectangle &> ( box ). Print (); }
C++11では、Java と同様に、スーパークラスで宣言されたメソッドをオーバーライドすることはできません。また、メソッドを宣言して、それが基本クラスのメソッドをオーバーライドしていることをコンパイラーにチェックさせること
finalもできます。override
デルファイ
Delphiでは、メソッドのオーバーライドはoverrideディレクティブを使用して実行されますが、メソッドがdynamic ディレクティブまたはvirtualディレクティブでマークされている場合に限られます。
継承された予約語は、スーパークラスの動作を呼び出すときに呼び出す必要があります。
type
TRectangle = class private FLength : Double ; FWidth : Double ; public property Length read FLength write FLength ; property Width read FWidth write FWidth ;
手順印刷;仮想;終了;
TBox =クラス( TRectangle )パブリックプロシージャPrint ;オーバーライド;終了;
エッフェル
Eiffelでは、機能の再定義はC++ や Java のメソッドのオーバーライドに類似しています。再定義は、再宣言として分類される機能の適応の 3 つの形式のうちの 1 つです。再宣言には、親クラスで延期 (抽象) された機能の実装が提供される有効化と、親で有効 (具象) だった機能が継承クラスで再び延期される未定義化も含まれます。機能が再定義されると、機能名は継承クラスによって保持されますが、シグネチャ、契約 (前提条件と事後条件の制限を尊重)、実装などの機能のプロパティは継承クラスで異なります。継承機能の前駆体と呼ばれる親クラスの元の機能が有効である場合、継承クラスで再定義された機能が有効になります。前駆体が延期されている場合、継承クラスの機能は延期されます。[8]
message以下の例のように、機能を再定義する意図は、inherit継承クラスの句で明示的に宣言する必要があります。
class
THOUGHT feature message -- 思考メッセージを表示するdo print ( "平行宇宙に斜めに駐車しているような気がする。%N" ) end end
class
ADVICE inherit THOUGHT redefine message end feature message -- 先行処理do print ( "警告: カレンダーの日付は表示されているよりも近いです。%N" ) end end
クラス では、ADVICE機能にはmessage、クラス 内の先行機能とは異なる実装が与えられますTHOUGHT。
THOUGHTと の両方のインスタンスを使用するクラスを考えてみましょうADVICE。
class
APPLICATION create make feature make -- アプリケーションを実行します。do ( create { THOUGHT } ). message ; ( create { ADVICE }). message end end
インスタンス化されると、クラスはAPPLICATION次の出力を生成します。
まるで平行宇宙に斜めに駐車しているような気分です。
注意: カレンダーの日付は、表示されている日付よりも近いです。
再定義された機能内では、言語キーワード を使用することで、その機能の先行機能にアクセスできますPrecursor。 の実装が次のように変更されたと仮定します。
{ADVICE}.message
メッセージ
-- 先行処理do print ( "警告: カレンダーの日付は表示されているよりも近いです。%N" )先行処理end
この機能の呼び出しには の実行が含まれるようになり、次の出力が生成されます。
{THOUGHT}.message
注意: カレンダーの日付は、表示されているよりも近いです。
まるで平行宇宙の斜めの場所に駐車しているような気がします。
ジャワ
Javaでは、サブクラスにスーパークラスのメソッドと同じシグネチャ (名前とパラメータ タイプ) を持つメソッドが含まれている場合、サブクラスのメソッドはスーパークラスのメソッドをオーバーライドします。例:
class Thought { public void message () { System . out . println ( "平行宇宙に斜めに駐車しているような気がする。" ); } }
public class Advice extends Thought { @Override // Java 5 の @Override アノテーションはオプションですが役に立ちます。public void message () { System . out . println ( "警告:カレンダーの日付は表示されている日付よりも近いです。" ); } }
クラスはThoughtスーパークラスを表し、メソッド呼び出しを実装します。 と呼ばれるサブクラスは、クラスにある可能性のあるすべてのメソッドを継承します。 クラスはメソッドをオーバーライドし、その機能を から置き換えます。
message()AdviceThoughtAdvicemessage()Thought
Thought parking = new Thought (); parking . message (); // 「平行宇宙に斜めに駐車しているような気がする。」と出力します。
考えましたdates = new Advice (); // ポリモーフィズムdates . message (); // 「警告: カレンダーの日付は、表示されている日付よりも近いです。」と出力します。
サブクラスにスーパークラスのメソッドをオーバーライドするメソッドが含まれている場合、その(スーパークラスの)オーバーライドされたメソッドは、キーワードを super使用してサブクラスのメソッド内から明示的に呼び出すことができます。[3](スーパークラスと関係のないクラスに属するメソッドから明示的に呼び出すことはできません。)super参照は
public class Advice extends Thought { @Override public void message () { System . out . println ( "警告: カレンダーの日付は表示されている日付よりも近いです。" ); super . message (); // メソッドの親バージョンを呼び出します。}
サブクラスがオーバーライドできないメソッドがあります。たとえば、Javaでは、スーパークラスでfinalと宣言されたメソッドはオーバーライドできません。また、privateまたはstaticと宣言されたメソッドも暗黙的にfinalであるためオーバーライドできません。finalと宣言されたクラスがスーパークラスになることも不可能です。[9]
コトリン
Kotlinでは、次のように関数をオーバーライドするだけで済みます (関数は でなければならないことに注意してくださいopen)。
fun main ( ) { val p = Parent ( 5 ) val c = Child ( 6 ) p.myFun ( ) c.myFun ( ) }
オープンクラスParent ( val a : Int ) {オープンfun myFun ( ) = println ( a ) }
クラスChild ( val b : Int ) : Parent ( b ) { override fun myFun () = println ( "オーバーライドされたメソッド" ) }
パイソン
Pythonでは、サブクラスにスーパークラスのメソッドをオーバーライドするメソッドが含まれている場合、の代わりに[10]を呼び出すことでスーパークラスのメソッドを呼び出すこともできます。例:
super(Subclass, self).methodself.method
class Thought :
def __init__ ( self ) -> None :
print ( "私は Thought 型の新しいオブジェクトです!" )
def message ( self ) -> None :
print ( "私は並行宇宙に斜めに駐車しているように感じます。" )
クラス Advice ( Thought ):
def __init__ ( self ) -> None :
super ( Advice , self ) . __init__ ()
def message ( self ) -> None :
print ( "警告: カレンダーの日付は表示されているよりも近いです" )
super ( Advice , self ) . message ()
t = Thought ()
# 「私は Thought 型の新しいオブジェクトです!」
t . message ()
# 「私は平行宇宙の斜めに駐車されているように感じます。
a = Advice ()
# "私は Thought 型の新しいオブジェクトです!"
a . message ()
# "警告: カレンダーの日付は見た目よりも近いです"
# "まるで平行宇宙の斜めに駐車されているような気がします。
# ------------------
# イントロスペクション:
isinstance ( t , 思考)
# 真
isinstance ( a , アドバイス)
# True
isinstance ( a , Thought )
# 真
ルビー
Rubyでは、サブクラスにスーパークラスのメソッドをオーバーライドするメソッドが含まれている場合、オーバーライドされたメソッドで super を呼び出すことによって、スーパークラスのメソッドを呼び出すこともできます。オーバーライドされたメソッドをオーバーライド メソッドの外部で使用できるようにしたい場合は、以下の 'super_message' に示すように、エイリアスを使用できます。
例:
class Thought def message puts "私は平行宇宙に斜めに駐車しているように感じます。" end end
class Advice < Thought alias :super_message :message def message puts "警告: カレンダーの日付は表示されているよりも近いです" super end end
注記
- ^ Zhang, Jie (2015). 「WWW でのオープンデータ通信のための新しい P2P オーバーライド API」2015 IEEE 国際コンシューマーエレクトロニクス会議 - 台湾pp. 156–157. doi :10.1109/ICCE-TW.2015.7216830. ISBN 978-1-4799-8745-0. S2CID 23295793。
- ^ フラナガン 2002、107 ページ
- ^ルイス&ロフタス 2006、p.454より
- ^ Overbey, J (2011). 「差分前提条件チェック: リファクタリング ツール用の軽量で再利用可能な分析」2011 第 26 回 IEEE/ACM 国際自動ソフトウェア エンジニアリング会議 (ASE 2011)。pp. 303–312。doi :10.1109/ ASE.2011.6100067。ISBN 978-1-4577-1639-3. S2CID 5933208。
- ^ Li, K (2014). 「残余調査: 予測的かつ正確なバグ検出」. ACM Transactions on Software Engineering and Methodology . 24 (2). doi :10.1145/2656201. S2CID 47112802.
- ^ メッセンベック、ハンスペーター (2002-03-25)。 「高度な C#: メソッドのオーバーライド」(PDF)。システムソフトウェア研究所、リンツのヨハネス・ケプラー大学、Fachbereich Informatik。ページ 6–8 。2011 年 8 月 2 日に取得。
- ^ マリク 2006、676 ページ
- ^ マイヤー 2009、572-575 ページ
- ^ デイテル&デイテル 2001、p.474
- ^ Python 3 の場合 - https://docs.python.org/3/library/functions.html#super を参照。2018 年 10 月 26 日にWayback Machineにアーカイブされました。
super().method
参照
- 実装の継承
- 継承セマンティクス
- メソッドのオーバーロード
- オブジェクト指向プログラミングにおけるポリモーフィズム
- テンプレートメソッドパターン
- 仮想継承
- X-HTTP-Method-Override HTTP ヘッダー
参考文献
- Deitel, H. M & Deitel, PJ(2001)。『Java プログラミング方法(第 4 版)』。アッパー サドル リバー、ニュージャージー: Prentice Hall。
- Lewis, J. & Loftus, W. (2008). Java: ソフトウェア ソリューション(第 6 版). ボストン、マサチューセッツ州: Pearson Addison Wesley.
- Malik, DS(2006)。C ++ プログラミング: データ構造を含むプログラム設計。 (第 3 版)。ワシントン DC: Course Technology。
- Flanagan, David.(2002). Java in a Nutshell. http://oreilly.com/catalog/9780596002831/preview#preview から取得
- マイヤー、ベルトラン(2009)。『Touch of Class: オブジェクトとコントラクトでプログラミングを学ぶ』。シュプリンガー。
外部リンク
- Nirosh LwC による OOP の概念とその他についての紹介
- Sun Microsystemsによるメソッドのオーバーライドと非表示
