抽象関数と仮想関数の違いは何ですか?仮想または抽象の使用が推奨されるのはどの場合ですか?どちらが最善のアプローチですか?
抽象関数と仮想関数の違いは何ですか?仮想または抽象の使用が推奨されるのはどの場合ですか?どちらが最善のアプローチですか?
回答:
抽象関数は機能を持つことができません。基本的に言って、すべての子クラスはこのメソッドの独自のバージョンを提供する必要がありますが、親クラスで実装しようとすることさえ一般的です。
仮想関数は、基本的には見た目ですが、ここでは子クラスにとって十分かそうでない機能があります。それで十分であれば、このメソッドを使用し、そうでなければ、私をオーバーライドして、独自の機能を提供します。
抽象関数は実装されておらず、抽象クラスでのみ宣言できます。これにより、派生クラスは強制的に実装を提供します。
仮想関数はデフォルトの実装を提供し、抽象クラスまたは非抽象クラスのいずれかに存在できます。
だから例えば:
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();
}
MyBase
クラスは抽象クラスを実装する必要はありませんか?私はこれを頻繁にしないので、私は誤解される可能性があります。あなたの例ではそれはわかりません。
abstract
を持つことができるのはクラスだけabstract
です。abstract
継承するクラスabstract
のクラスがなければならない override
そのabstract
メンバー。abstract
メンバーは、暗黙的ですvirtual
。abstract
メンバーは、(任意の実装を提供することはできませんabstract
と呼ばれているpure virtual
いくつかの言語で)。virtual
もかまいませんvirtual
。abstract
メンバー(すなわち抽象的性質、抽象メソッドは)つまりは、あなたがそれ自体で、デフォルトの実装を有していないことを除いて、それを上書きすることができ、単に仮想メソッドのようなものです。
常に抽象関数をオーバーライドする必要があります。
したがって:
抽象メソッド:クラスに抽象メソッドが含まれている場合、そのクラスは抽象として宣言する必要があります。抽象メソッドには実装がないため、その抽象クラスから派生するクラスは、この抽象メソッドの実装を提供する必要があります。
仮想メソッド:クラスは仮想メソッドを持つことができます。仮想メソッドには実装があります。仮想メソッドを持つクラスから継承する場合、仮想メソッドをオーバーライドして追加のロジックを提供するか、ロジックを独自の実装に置き換えることができます。
何を使用するか:場合によっては、特定の型に特定のメソッドが必要であることがわかっていますが、このメソッドがどのような実装を持つ必要があるかはわかりません。
このような場合、このシグネチャを持つメソッドを含むインターフェースを作成できます。ただし、そのようなケースがあり、そのインターフェースのインプリメンターが別の一般的なメソッド(すでに実装を提供できる)も持っていることがわかっている場合は、抽象クラスを作成できます。この抽象クラスには、抽象メソッド(オーバーライドする必要があります)と、「共通」ロジックを含む別のメソッドが含まれます。
必須ではありませんが、直接使用できるが、継承者が特定の動作を変更できるようにするクラスがある場合は、仮想メソッドを使用する必要があります。
説明:類推あり。うまくいけば、それはあなたを助けるでしょう。
環境
私は建物の21階で働いています。そして、私は火について妄想的です。時々、世界のどこかで、火が空のスクレーパーを燃やしています。しかし、幸運なことに、火災が発生した場合の対処方法については、次の場所に取扱説明書があります。
FireEscape()
これは基本的にはFireEscape()と呼ばれる仮想メソッドです
仮想メソッド
この計画は、99%の状況に非常に適しています。それが機能する基本的な計画です。しかし、1%の確率でファイアエスケープがブロックまたは損傷します。この場合、完全にねじ込まれ、思い切った操作を行わないとトーストになります。仮想メソッドを使用すると、それを行うことができます。基本的なFireEscape()プランを独自のバージョンのプランでオーバーライドできます。
言い換えると、仮想メソッドは基本的な計画を提供し、必要に応じてオーバーライドできます。プログラマーが適切と判断した場合、サブクラスは親クラスの仮想メソッドをオーバーライドできます。
抽象メソッド
すべての組織が十分に訓練されているわけではありません。消防訓練を行わない組織もあります。彼らは全体的な脱出ポリシーを持っていません。すべての人は自分のためです。経営者は、そのような既存の方針にのみ関心があります。
言い換えれば、それぞれの人がされて強制的に彼自身のFireEscape()メソッドを開発します。1人の男がファイアエスケープを歩きます。別の男がパラシュートします。別の男は、ロケット推進技術を使用して建物から離れて飛びます。別の男がアブセイルします。基本的なFireEscape()計画がある限り、経営者はどのように脱出するかを気にしません-もしそうでなければ、OHSが大量のレンガのように組織に降りてくることが保証されます。これは、抽象メソッドが意味するものです。
2つの違いは何ですか?
抽象メソッド:サブクラスがされて強制的に自分の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");
}
}
}
バインディングは、名前をコードのユニットにマッピングするプロセスです。
レイトバインディングとは、名前を使用するがマッピングは延期することを意味します。言い換えると、最初に名前を作成/メンションし、その後のいくつかのプロセスにその名前へのコードのマッピングを処理させます。
今検討してください:
つまり、短い答えはvirtual
、マシン(実行時)abstract
に対する遅延バインディングの指示であるのに対して、人間(プログラマ)に対する遅延バインディングの指示です。
つまり、次のvirtual
ことを意味します。
「親愛なるランタイム、あなたが最善を尽くすことを行うことによって適切なコードをこの名前にバインドします:検索」
のabstract
意味:
「親愛なるプログラマー、あなたが最善を尽くすことを行うことによってこの名前に適切なコードをバインドしてください:発明」
完全を期すために、オーバーロードとは次のことを意味します。
「親愛なるコンパイラ、あなたが最善を尽くすことを行うことによって適切なコードをこの名前にバインドします:ソート」。
仮想メソッド:
仮想とは、それを上書きできることを意味します。
仮想機能には実装があります。クラスを継承すると、仮想関数をオーバーライドして独自のロジックを提供できます。
抽象メソッド
抽象とは、オーバーライドする必要があることを意味します。
抽象関数には実装がなく、抽象クラスになければなりません。
宣言のみ可能です。これにより、派生クラスはその実装を提供します。
抽象メンバーは暗黙的に仮想です。一部の言語では、アブストラクトを純粋仮想として呼び出すことができます。
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
いくつかの場所で、抽象メソッドが以下のように定義されているのを見てきました。**
「抽象メソッドは子クラスに実装する必要があります」
**のように感じました。
子クラスも抽象である場合、抽象メソッドを子クラスに実装する必要はありません。
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は軍の上位にいます。彼は戦いの意味を定義しました:
問題は、それが非常に一般的な方法であることです。これは機能する優れた方法ですが、十分に具体的でない場合もあります。ペトラエウスにとって良いことは、彼の命令には余裕と範囲があることです-彼は他の人が彼らの特定の要件に従って彼の「戦い」の定義を変更することを許可しました。
Private Job Bloggsはペトラエウスの命令を読み、彼の特定の要件に従って、彼自身のバージョンの戦いを実装する許可を与えられています。
ヌーリアルマリキもペトラエウスから同じ注文を受けました。彼はまた戦うことです。しかし、彼は政治家であり、歩兵ではありません。明らかに彼は政治家の敵を頭の中で撃ち回ることはできません。ペトレウスは彼に仮想メソッドを与えたので、マリキは彼の特定の状況に従って、彼自身のバージョンのfightメソッドを実装することができます:
言い換えると、仮想メソッドは定型的な指示を提供しますが、これらは一般的な指示であり、特定の状況に応じて、軍の階層の下の人々がより具体的にすることができます。
2つの違い
George Bushは実装の詳細を証明していません。これは他の誰かが提供する必要があります。これは抽象メソッドです。
一方、Petraeus は実装の詳細を提供しますが、部下がより良い何かを思い付くことができる場合は、自分の注文を自分のバージョンで上書きすることを部下に許可しました。
お役に立てば幸いです。
抽象関数は本体を持つことができず、子クラスによってオーバーライドされる必要があります
仮想関数には本体があり、子クラスによってオーバーライドされる場合とオーバーライドされない場合があります
一般的なオブジェクト指向の視点から:
抽象メソッドについて:親クラスに抽象メソッドを配置すると、実際には子クラスに対して次のように言われます。このようなメソッドシグネチャがあることに注意してください。そして、それを使用したい場合は、独自に実装する必要があります!
仮想関数について:親クラスに仮想メソッドを配置すると、派生クラスに対して次のように言うことになります:ここで、何かを行う機能があります。これが便利な場合は、そのまま使用してください。そうでない場合は、これをオーバーライドしてコードを実装してください。コードで私の実装を使用することもできます。
これは、一般的なオブジェクト指向のこの2つの概念の違いに関するいくつかの哲学です。
C#には仮想クラスの呼び出しはありません。
機能について
あなたはあなたの要件で決めることができます。
抽象メソッドには実装がなく、親クラスで宣言されています。子クラスは、そのメソッドを実装する責任があります。
仮想メソッドは、親クラスに実装を持つ必要があり、それにより、子クラスは、親クラスのその実装を使用するか、子クラスのそのメソッドにそれ自体の新しい実装を持つかを選択できるようになります。
抽象関数またはメソッドは、クラスによって公開されるパブリックな「操作の名前」であり、その目的は、抽象クラスとともに、オブジェクトが実装する必要のある構造に対するオブジェクト設計における制約の形式を主に提供します。
実際、その抽象クラスから継承するクラスは、このメソッドに実装を提供する必要があります。通常、コンパイラは、そうでない場合にエラーを発生させます。
抽象クラスとメソッドを使用することは、クラスを設計するときに実装の詳細に焦点を当てることにより、クラス構造が実装に関連しすぎて、依存関係を作成し、それらの間で協調するクラス間の結合を回避するために、主に重要です。
仮想関数または仮想メソッドは、単にクラスのパブリック動作をモデル化するメソッドですが、子クラスはその動作に特定の拡張機能を実装する必要があると考えられるため、継承チェーンでそれを自由に変更できます。
これらは両方とも、オブジェクト指向パラダイムにおける多形の形式を表しています。
抽象メソッドと仮想関数を一緒に使用して、優れた継承モデルをサポートできます。
ソリューションの主要なオブジェクトの適切な抽象的な構造を設計し、さらに特殊化しやすいものを見つけて基本的な実装を作成し、これらを仮想化します。最後に、継承された仮想化を最終的に「オーバーライド」して基本的な実装を特殊化します。
ここでは、インターフェイス、抽象クラス、および通常のクラスの動作を非常に基本的なレベルで確認するための具体的な例になることを期待して、いくつかのサンプルコードを書いています。デモとして使用する場合は、このコードをプロジェクトとしてgithubで見つけることもできます。https://github.com/usavas/JavaAbstractAndInterfaceDemo
public interface ExampleInterface {
// public void MethodBodyInInterfaceNotPossible(){
// }
void MethodInInterface();
}
public abstract class AbstractClass {
public abstract void AbstractMethod();
// public abstract void AbstractMethodWithBodyNotPossible(){
//
// };
//Standard Method CAN be declared in AbstractClass
public void StandardMethod(){
System.out.println("Standard Method in AbstractClass (super) runs");
}
}
public class ConcreteClass
extends AbstractClass
implements ExampleInterface{
//Abstract Method HAS TO be IMPLEMENTED in child class. Implemented by ConcreteClass
@Override
public void AbstractMethod() {
System.out.println("AbstractMethod overridden runs");
}
//Standard Method CAN be OVERRIDDEN.
@Override
public void StandardMethod() {
super.StandardMethod();
System.out.println("StandardMethod overridden in ConcreteClass runs");
}
public void ConcreteMethod(){
System.out.println("Concrete method runs");
}
//A method in interface HAS TO be IMPLEMENTED in implementer class.
@Override
public void MethodInInterface() {
System.out.println("MethodInInterface Implemented by ConcreteClass runs");
// Cannot declare abstract method in a concrete class
// public abstract void AbstractMethodDeclarationInConcreteClassNotPossible(){
//
// }
}
}