抽象メソッドと仮想メソッドの違いは何ですか? 抽象メソッドまたは仮想メソッドの使用が推奨されるのはどのような場合ですか? どれが最良のアプローチですか?
28 に答える
抽象関数は機能を持つことができません。基本的に、子クラスはこのメソッドの独自のバージョンを提供する必要があると言っていますが、親クラスに実装しようとするのは一般的すぎます。
仮想関数は、基本的に見て、子クラスにとって十分である場合とそうでない場合がある機能を示しています。したがって、それで十分な場合はこのメソッドを使用し、そうでない場合は私をオーバーライドして、独自の機能を提供してください。
抽象関数には実装がなく、抽象クラスでのみ宣言できます。これにより、派生クラスは強制的に実装を提供します。
仮想関数はデフォルトの実装を提供し、抽象クラスまたは非抽象クラスのいずれかに存在できます。
たとえば、次のようになります。
public abstract class myBase
{
//If you derive from this class you must implement this method. notice we have no method body here either
public abstract void YouMustImplement();
//If you derive from this class you can change the behavior but are not required to
public virtual void YouCanOverride()
{
}
}
public class MyBase
{
//This will not compile because you cannot have an abstract method in a non-abstract class
public abstract void YouMustImplement();
}
abstract
クラスのみがabstract
メンバーを持つことができます。abstract
クラスから継承する非abstract
クラスは、そのメンバーである必要があります。override
abstract
abstract
メンバーは暗黙的にvirtual
です。abstract
メンバーは実装を提供できません(一部の言語でabstract
は呼び出さpure virtual
れます)。
抽象関数は常にオーバーライドする必要があります。
したがって:
- 抽象関数-継承者が独自の実装を提供する必要がある場合
- Virtual -継承者が決定する場合
抽象関数:
- 抽象クラス内でのみ宣言できます。
- 抽象クラスの実装ではなく、メソッド宣言のみが含まれます。
- 派生クラスでオーバーライドする必要があります。
仮想機能:
- 非抽象クラスだけでなく、抽象クラス内でも宣言できます。
- メソッドの実装が含まれています。
- オーバーライドされる可能性があります。
説明:アナロジーで。うまくいけば、それはあなたを助けます。
環境
ビルの21階で働いています。そして、私は火について妄想的です。時々、世界のどこかで、高層ビルが火事で焼かれています。しかし幸いなことに、火災の場合の対処法に関する取扱説明書がここのどこかにあります。
ファイアエスケープ()
- 持ち物を集めない
- 非常階段まで歩く
- 建物の外に出る
これは基本的にFireEscape()と呼ばれる仮想メソッドです。
仮想メソッド
この計画は、99% の状況に適しています。活躍するベーシックプランです。しかし、1% の確率でファイア エスケープがブロックされるか損傷する可能性があります。仮想メソッドを使用すると、まさにそれを行うことができます。基本的な FireEscape() プランを独自のバージョンのプランでオーバーライドできます。
- ウィンドウに実行
- 窓から飛び降りる
- 安全に下までパラシュートで降りる
つまり、仮想メソッドは、必要に応じてオーバーライドできる基本的な計画を提供します。サブクラスは、プログラマが適切と判断した場合、親クラスの仮想メソッドをオーバーライドできます。
抽象メソッド
すべての組織が十分に訓練されているわけではありません。一部の組織は消防訓練を行いません。全体的なエスケープ ポリシーはありません。すべての人は自分のためです。経営陣は、そのようなポリシーが存在することにのみ関心があります。
つまり、各自が独自のFireEscape () メソッドを開発する必要があります。一人の男が非常階段から出てきます。別の男がパラシュートします。別の男は、ロケット推進技術を使って建物から飛び去ります。別の男が懸垂下降します。あなたが基本的な FireEscape() 計画を持っている限り、経営陣はあなたがどのように脱出するかを気にしません。これが抽象メソッドの意味です。
両者の違いは何ですか?
抽象メソッド: サブクラスは、独自の FireEscape メソッドを実装する必要があります。仮想メソッドを使用すると、基本的な計画が待っていますが、十分でない場合は独自の計画を実装することを選択できます。
それほど難しくはありませんでしたか?
抽象メソッド:クラスに抽象メソッドが含まれている場合、そのクラスは抽象として宣言する必要があります。抽象メソッドには実装がないため、その抽象クラスから派生するクラスは、この抽象メソッドの実装を提供する必要があります。
仮想メソッド:クラスは仮想メソッドを持つことができます。仮想メソッドには実装があります。仮想メソッドを持つクラスから継承する場合は、仮想メソッドをオーバーライドして追加のロジックを提供するか、ロジックを独自の実装に置き換えることができます。
いつ使用するか:場合によっては、特定の型に特定のメソッドが必要であることはわかっていますが、このメソッドにどのような実装が必要かはわかりません。
このような場合、このシグニチャを持つメソッドを含むインターフェースを作成できます。ただし、そのような場合でも、そのインターフェイスの実装者が別の一般的なメソッド(すでに実装を提供できる)を持っていることがわかっている場合は、抽象クラスを作成できます。この抽象クラスには、抽象メソッド(オーバーライドする必要があります)と、「共通」ロジックを含む別のメソッドが含まれます。
直接使用できるクラスがあるが、必須ではありませんが、継承者が特定の動作を変更できるようにする場合は、仮想メソッドを使用する必要があります。
抽象メソッドは、具体的なクラスを作成するために実装する必要があるメソッドです。宣言は抽象クラスにあり (抽象メソッドを持つクラスはすべて抽象クラスでなければなりません)、具象クラスに実装する必要があります。
仮想メソッドは、スーパークラスの動作を置き換えて、オーバーライドを使用して派生クラスでオーバーライドできるメソッドです。オーバーライドしない場合は、元の動作が得られます。その場合、常に新しい動作が得られます。これは、オーバーライドできないが元のメソッドを隠すことができる非仮想メソッドとは対照的です。これはnew
修飾子を使用して行われます。
次の例を参照してください。
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
インスタンス化して、またはDerivedClass
を呼び出すと、 「こんにちは」と「またね」というメッセージが表示されます。に電話すると、「こんにちは」と「またね」が返ってきます。これは仮想であるためであり、派生クラスで置き換えることができます。は隠されているだけなので、基本クラスからそれを呼び出すと、元のメソッドが取得されます。SayHello
SayGoodbye
HelloGoodbye
SayGoodbye
SayHello
抽象メソッドは暗黙的に仮想です。それらは、インターフェイスが行うように、存在しなければならない動作を定義します。
抽象メソッドは常に仮想です。実装することはできません。
それが主な違いです。
基本的に、仮想メソッドの「デフォルト」実装があり、子孫がその動作を変更できるようにする場合は、仮想メソッドを使用します。
抽象メソッドを使用すると、子孫に実装を提供するように強制します。
次のクラスにいくつかの改善を加えることで、これをより簡単にしました(他の回答から):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestOO
{
class Program
{
static void Main(string[] args)
{
BaseClass _base = new BaseClass();
Console.WriteLine("Calling virtual method directly");
_base.SayHello();
Console.WriteLine("Calling single method directly");
_base.SayGoodbye();
DerivedClass _derived = new DerivedClass();
Console.WriteLine("Calling new method from derived class");
_derived.SayHello();
Console.WriteLine("Calling overrided method from derived class");
_derived.SayGoodbye();
DerivedClass2 _derived2 = new DerivedClass2();
Console.WriteLine("Calling new method from derived2 class");
_derived2.SayHello();
Console.WriteLine("Calling overrided method from derived2 class");
_derived2.SayGoodbye();
Console.ReadLine();
}
}
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye\n");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public abstract class AbstractClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
//public virtual void SayGoodbye()
//{
// Console.WriteLine("Goodbye\n");
//}
public abstract void SayGoodbye();
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
public class DerivedClass2 : AbstractClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
// We should use the override keyword with abstract types
//public new void SayGoodbye()
//{
// Console.WriteLine("See you later2");
//}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
}
継承者が必要に応じて機能を拡張する場合は、基本的に仮想メソッドを使用します。
継承者に機能を実装させたい場合は、抽象メソッドを使用します(この場合、継承者には選択の余地がありません)。
いくつかの場所で、抽象メソッドが次のように定義されているのを見てきました。**
「抽象メソッドは、子クラスに実装する必要があります」
** のように感じました。
子クラスも抽象である場合、子クラスに抽象メソッドを実装する必要はありません。
1) 抽象メソッドをプライベート メソッドにすることはできません。2) 抽象メソッドは、同じ抽象クラスに実装できません。
..抽象クラスを実装している場合は、基本抽象クラスから抽象メソッドをオーバーライドする必要があります。なぜなら..抽象メソッドの実装はオーバーライドキーワード.仮想メソッドに似ています。
継承されたクラスで仮想メソッドを実装する必要はありません。
----------CODE--------------
public abstract class BaseClass
{
public int MyProperty { get; set; }
protected abstract void MyAbstractMethod();
public virtual void MyVirtualMethod()
{
var x = 3 + 4;
}
}
public abstract class myClassA : BaseClass
{
public int MyProperty { get; set; }
//not necessary to implement an abstract method if the child class is also abstract.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
public class myClassB : BaseClass
{
public int MyProperty { get; set; }
//You must have to implement the abstract method since this class is not an abstract class.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
上記の例のほとんどはコードを使用しており、非常に優れています。彼らの言うことに付け加える必要はありませんが、以下はコード/技術用語ではなく類推を利用した簡単な説明です。
簡単な説明 - 類推による説明
抽象メソッド
ジョージ・W・ブッシュを考えてみてください。彼は兵士たちに「イラクで戦え」と言います。以上です。彼が指定したのは、戦う必要があるということだけです。彼はそれがどのように起こるかを正確に指定していません。しかし、ただ外に出て「戦う」ことはできません。それは正確にはどういう意味ですか? B-52 と戦うか、デリンジャーと戦うか。それらの具体的な詳細は他の人に任せます。これは抽象メソッドです。
仮想メソッド
David Petraeus は軍の高官です。彼は戦いの意味を次のように定義しています。
- 敵を見つける
- 彼を無力化します。
- 後はビールをどうぞ
問題は、それが非常に一般的な方法であることです。これは有効な方法ですが、十分に具体的でない場合もあります。Petraeus にとって良いことは、彼の命令に余裕と範囲があることです。彼は、特定の要件に応じて、他の人が「戦う」という彼の定義を変更できるようにしました。
Private Job Bloggs は Petraeus の命令を読み、彼の特定の要件に従って、彼独自のバージョンの戦いを実装する許可を与えられます。
- 敵を見つける。
- 彼の頭を撃ちます。
- 家に帰れ
- ビールをどうぞ。
Nouri al Maliki も、Petraeus から同じ注文を受けます。彼も戦うことになっています。しかし、彼は歩兵ではなく政治家です。明らかに、彼は政治家の敵の頭を撃ちまくるわけにはいきません。Petraeus が彼に仮想メソッドを与えたので、Maliki は特定の状況に応じて、独自のバージョンの戦闘メソッドを実装できます。
- 敵を見つける。
- でっちあげの罪状で彼を逮捕させてください。
- 家に帰れ
- ビールをどうぞ。
言い換えれば、仮想メソッドは定型的な指示を提供しますが、これらは一般的な指示であり、特定の状況に応じて、軍の階層の下の人々によってより具体的にすることができます.
両者の違い
ジョージ・ブッシュは実装の詳細を証明していません。これは他の誰かが提供する必要があります。これは抽象メソッドです。
一方、Petraeus は実装の詳細を提供していますが、部下がより良いものを思いつくことができれば、自分のバージョンで彼の命令を上書きする許可を与えています.
それが役立つことを願っています。
抽象関数(メソッド) :
● 抽象メソッドは、abstract キーワードで宣言されたメソッドです。
●本体はありません。
● 派生クラスで実装する必要があります。
● メソッドが抽象の場合、クラスは抽象化する必要があります。
仮想関数 (メソッド) :
● 仮想メソッドとは、virtual キーワードで宣言されたメソッドであり、override キーワードを使用して派生クラス メソッドでオーバーライドできます。
● オーバーライドするかどうかは、派生クラス次第です。
一般的なオブジェクト指向の観点から:
抽象メソッドについて: 親クラスに抽象メソッドを配置すると、実際には子クラスに言っていることになります: このようなメソッド シグネチャがあることに注意してください。そして、それを使用したい場合は、独自に実装する必要があります!
仮想関数について:親クラスに仮想メソッドを配置すると、派生クラスに言っていることになります:ねえ、あなたのために何かをする機能がここにあります。これが役立つ場合は、それを使用してください。そうでない場合は、これをオーバーライドしてコードを実装します。コードで私の実装を使用することもできます。
これは、一般的な OO におけるこの 2 つの概念の違いについての哲学です。
C# には仮想クラスというものはありません。
関数の場合
- 抽象関数には署名のみがあり、ドライブ クラスは機能をオーバーライドする必要があります。
- 仮想機能は、ドライブ クラスが要件に応じてそれをオーバーライドする場合としない場合がある機能の一部を保持します。
あなたの要件で決めることができます。
私の理解では:
抽象メソッド:
抽象クラスのみが抽象メソッドを保持できます。また、派生クラスはメソッドを実装する必要があり、クラスには実装が提供されていません。
仮想メソッド:
クラスはこれらを宣言し、同じ実装を提供することもできます。また、派生クラスは、それをオーバーライドするメソッドを実装する必要があります。