web-dev-qa-db-ja.com

抽象機能と仮想機能の違いは何ですか?

抽象機能と仮想機能の違いは何ですか?どの場合に、仮想または抽象の使用をお勧めしますか?どれが最善のアプローチですか?

1458
Moran Helman

抽象関数は機能を持つことができません。 あなたは基本的に言って、どの子クラスもこのメソッドの独自のバージョンを与えなければなりません、しかし親クラスで実装しようとさえすることはあまりに一般的です。 

仮想関数 は基本的に見た目を言っている、これは子クラスには十分かもしれないし、十分でないかもしれない機能性である。それで十分であれば、そうでなければこのメソッドを使ってから私をオーバーライドし、あなた自身の機能を提供してください。

2477
BFree

抽象関数は実装されておらず、抽象クラスでしか宣言できません。これは派生クラスに実装の提供を強制します。仮想関数はデフォルト実装を提供し、抽象クラスまたは非抽象クラスのどちらにも存在できます。だから、例えば:

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();
}
264
JoshBerke
  1. abstractクラスだけがabstractメンバーを持つことができます。
  2. abstractクラスから継承する非abstractクラス must overrideそのabstractメンバー。
  3. abstractメンバーは暗黙的にvirtualです。
  4. abstractメンバーは実装を提供できません(一部の言語ではabstractpure virtualと呼ばれます)。
75
Mehrdad Afshari

常に抽象関数をオーバーライドする必要があります。

したがって:

  • 抽象関数 - when 継承者は独自の実装を提供しなければならない
  • Virtual - when 決定するのは継承者次第です
57
Rinat Abdullin

抽象的な機能:

  1. 抽象クラス内でのみ宣言できます。 
  2. 抽象クラスでの実装ではなく、メソッド宣言のみを含みます。 
  3. 派生クラスでオーバーライドする必要があります。

仮想機能:

  1. 非抽象クラスと同様に抽象クラス内でも宣言できます。
  2. メソッドの実装が含まれています。
  3. 上書きされる可能性があります。
34
Lexnim

抽象メソッド:クラスに抽象メソッドが含まれる場合、そのクラスを抽象として宣言する必要があります。抽象メソッドには実装がないため、その抽象クラスから派生するクラスは、この抽象メソッドの実装を提供する必要があります。

仮想メソッド:クラスは仮想メソッドを持つことができます。仮想メソッドには実装があります。仮想メソッドを持つクラスから継承する場合、can仮想メソッドをオーバーライドして追加のロジックを提供するか、ロジックを独自の実装に置き換えます。

何を使用するか:場合によっては、特定の型に特定のメソッドが必要であることは知っていますが、このメソッドにどのような実装が必要かはわかりません。
このような場合、このシグネチャを持つメソッドを含むインターフェースを作成できます。ただし、そのような場合でも、そのインターフェイスの実装者が別の一般的なメソッド(既に実装を提供できる)を持っていることがわかっている場合は、抽象クラスを作成できます。この抽象クラスには、抽象メソッド(オーバーライドする必要があります)、および「共通」ロジックを含む別のメソッドが含まれます。

直接使用できるが、継承者が特定の動作を変更できるようにするクラスがある場合は、仮想メソッドを使用する必要がありますが、必須ではありません。

29

説明:類推で。うまくいけばそれがあなたを助けるでしょう。

コンテキスト

私は建物の21階で働いています。そして、私は火について妄想しています。時々、世界のどこかで、スカイスクレイパーが火で燃えています。しかし、幸いなことに、火事の場合の対処方法については、取扱説明書がここにあります。

FireEscape()

  1. 持ち物を収集しない
  2. ファイアーエスケープへ歩く
  3. 建物から出る

これは基本的にFireEscape()と呼ばれる仮想メソッドです

仮想メソッド

この計画は、99%の状況に適しています。それは機能する基本的な計画です。ただし、1%の確率でファイアエスケープがブロックされるか破損する可能性があります。その場合、完全にねじ込まれ、抜本的なアクションをとらない限りトーストになります。仮想メソッドを使用すると、それだけを実行できます。基本的なFireEscape()プランを独自のバージョンのプランでオーバーライドできます。

  1. ウィンドウまで実行
  2. 窓から飛び出す
  3. 安全に下にパラシュート

言い換えれば、仮想メソッドは基本的なプランを提供し、必要に応じてオーバーライドできます。プログラマが適切と判断した場合、サブクラスは親クラスの仮想メソッドをオーバーライドできます。

抽象メソッド

すべての組織が十分に訓練されているわけではありません。一部の組織は、ファイアドリルを行いません。全体的なエスケープポリシーはありません。すべての人は自分自身のためです。経営者は、このようなポリシーが存在することにのみ関心があります。

言い換えると、各人はforcedであり、独自のFireEscape()メソッドを開発します。一人の男が避難所から出て行きます。別の男がパラシュートします。別の男はロケット推進技術を使用して建物から飛び立ちます。別の男が抜け出します。経営陣は気にしませんhow基本的なFireEscape()プランがある限り、あなたは逃げます。これが抽象メソッドの意味です。

2つの違いは何ですか?

抽象メソッド:サブクラスは、独自のFireEscapeメソッドを実装するためのforcedです。仮想メソッドでは、基本的なプランが用意されていますが、十分でない場合は独自に実装するを選択できます。

さて、それはそれほど難しくありませんでしたか?

26
BKSpurgeon

抽象メソッドは、具象クラスを作成するために実装しなければならないメソッドです。宣言は抽象クラス内にあり(そして抽象メソッドを持つクラスは抽象クラスでなければなりません)、それは具象クラスに実装されなければなりません。

仮想メソッドは、オーバーライドを使用して派生クラスでオーバーライドできるメソッドです。 置き換え /スーパークラスの動作。上書きしない場合は、元の動作になります。そうした場合、あなたはいつも新しい振る舞いをします。これは、仮想メソッドではなく、オーバーライドすることはできませんが、元のメソッドを非表示にすることはできません。これは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は隠されているだけなので、基本クラスからそれを呼び出すと、元のメソッドが得られます。

抽象メソッドは暗黙的に仮想的です。それらは、インターフェースがそうであるように、存在しなければならない振る舞いを定義します。

22
Kamiel Wanrooij

抽象メソッドは常に仮想的です。実装することはできません。

それが主な違いです。

基本的に、 'デフォルト'の実装があり、子孫がその振る舞いを変更できるようにしたい場合は、仮想メソッドを使用します。

抽象メソッドでは、子孫に実装の提供を強制します。

10
Rashack

私は(他の答えから)次のクラスにいくつかの改良を加えることによってこれをより簡単にしました:

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");
        }
    }
}
10
MeqDotNet

バインディング は、名前をコード単位にマップするプロセスです。

遅延バインディング は名前を使用しますが、マッピングを延期することを意味します。言い換えれば、最初に名前を作成/言及し、その後のいくつかのプロセスにその名前へのコードのマッピングを処理させます。

今考えてみましょう:

  • 人間と比較すると、機械は検索とソートに非常に優れています。
  • 機械と比較して、人間は発明と革新性が本当に得意です。

つまり、短い答えは次のとおりです。virtualはマシン(実行時)に対する遅延バインディング命令ですが、abstractは人間(プログラマ)に対する遅延バインディング命令です

言い換えれば、virtualは次のことを意味します。

「親愛なる runtime 、最善を尽くして適切なコードをこの名前にバインドします。 検索

abstractは次のことを意味します。

「親愛なる プログラマー 、最善を尽くして適切なコードをこの名前にバインドしてください: inventing

完全を期すために、 オーバーロード は次のようになります。

「親愛なる compiler 、最善を尽くして適切なコードをこの名前にバインドしてください: sort 」。

5
Rodrick Chapman

仮想メソッド

  • 仮想とは、上書きできることを意味します。  

  • 仮想機能には実装があります。クラスを継承すると、仮想関数をオーバーライドして独自のロジックを提供できます。 

  • 実装しながら仮想関数の戻り型を変更することができます
    子クラスでの機能(これはの概念として言えます
    シャドーイング)。

抽象メソッド

  • 抽象は、オーバーライドしなければならないことを意味します。  

  • 抽象関数は実装を持たず、抽象クラス内になければなりません。

  • 宣言することしかできません。これは派生クラスにその実装を提供するように強制します。 

  • 抽象メンバーは暗黙的に仮想です。要約は、一部の言語では純粋に仮想的と呼ぶことができます。

    public abstract class BaseClass
    { 
        protected abstract void xAbstractMethod();
    
        public virtual void xVirtualMethod()
        {
            var x = 3 + 4;
        }
    } 
    
3
flik

継承者に必要な機能を拡張させる場合は、基本的に仮想メソッドを使用します。

継承者に機能を実装させたい場合(そしてこの場合は選択できない場合)、抽象メソッドを使用します。

3
Brann

私はいくつかの場所で抽象メソッドが以下のように定義されているのを見ました。 **

"抽象メソッドは、子クラスに実装する必要があります"

** そう感じました。

抽象メソッドを子クラスで実装する必要はありません、子クラスも抽象である場合 .. 

1)抽象メソッドcantをプライベートメソッドにする[2]抽象メソッドcantを同じ抽象クラスに実装する。

抽象クラスを実装する場合は、基本抽象クラスの抽象メソッドをオーバーライドする必要があります。抽象メソッドの実装はoverride keyを使用する仮想方式に似ています。

仮想メソッドを継承クラスに実装する必要はありません。 

                                 ----------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();
    }
}
3
Kodoth

上記の例のほとんどはコードを使用しており、非常に優れています。私は彼らが言うことを追加する必要はありませんが、以下はコード/技術用語ではなく類推を利用する簡単な説明です。

簡単な説明-類推を使用した説明

抽象メソッド

ジョージWブッシュを考えてください。彼は兵士たちに「イラクで戦いに行け」と言います。以上です。彼が指定したのは、戦いをしなければならないということだけです。彼は正確にそれが起こることを指定しませんhow。しかし、私はあなたが外に出て「戦う」ことができないことを意味します:それは正確に何を意味するのでしょうか? B-52やデリンジャーと戦うのですか?これらの特定の詳細は他の人に任されています。これは抽象メソッドです。

仮想メソッド

デイビッド・ペトラウスは軍隊の最高位です。彼は戦いの意味を定義しました:

  1. 敵を見つける
  2. 彼を中和してください。
  3. その後ビールを飲む

問題は、それが非常に一般的な方法であるということです。これは有効な方法ですが、時には十分に具体的ではありません。ペトラエウスにとって良いことは、彼の命令に余裕と範囲があるということです。彼は、特定の要件に従って、他の人が「戦い」の定義を変更することを許可しています。

プライベートジョブブログはペトラエウスの命令を読み、特定の要件に従って、彼自身のバージョンの戦闘を実施する許可を与えられます。

  1. 敵を見つけます。
  2. 彼を頭の中で撃ちます。
  3. 家に帰る
  4. ビールを飲む。

ノウリアルマリキもペトラエウスから同じ注文を受けます。彼はまた戦うことです。しかし、彼は歩兵ではなく政治家です。明らかに、彼は頭の中で政治家の敵を撃つことはできません。 Petraeusが仮想メソッドを提供したため、Malikiは特定の状況に応じて、独自のバージョンのfightメソッドを実装できます。

  1. 敵を見つけます。
  2. 彼はいくつかのBSで告発された容疑で逮捕されました。
  3. 家に帰る
  4. ビールを飲む。

言い換えれば、仮想メソッドは定型的な指示を提供しますが、これらは一般的な指示であり、特定の状況に応じて、軍の階層の下にいる人々がより具体的に行うことができます。

2つの違い

  • ジョージブッシュは、実装の詳細を証明していません。これは他の誰かによって提供されなければなりません。これは抽象メソッドです。

  • 一方、Petraeusdoesは実装の詳細を提供しますが、部下に自分のバージョンで注文をオーバーライドする許可を与えました。より良いなにか。

それが役立つことを願っています。

2
BKSpurgeon

抽象関数 本体を持つことはできず、子クラスによってオーバーライドされる必要があります

仮想機能 本体を持ち、子クラスによってオーバーライドされる場合とされない場合がある

2

抽象機能(メソッド):

●抽象メソッドは、キーワードabstractで宣言されたメソッドです。

●体がありません。

●派生クラスで実装する必要があります。

●メソッドが抽象型の場合、クラスは抽象型になります。

仮想関数(メソッド):

●仮想メソッドは、キーワードvirtualで宣言されたメソッドであり、overrideキーワードを使用して派生クラスメソッドによってオーバーライドできます。

●オーバーライドするかどうかは、派生クラス次第です。

2
Kedarnath M S

抽象メソッドには実装がありません。親クラスで宣言されています。子クラスはそのメソッドを実装するために責任があります。

仮想メソッドは親クラスに実装を持つべきで、子クラスがその親クラスの実装を使用するか、それとも子クラスのそのメソッドに新しい実装を使用するかの選択を容易にします。

1
Vinay Chanumolu

抽象関数は、実装のない「単なる」シグネチャです。クラスの使用方法を宣言するためにインターフェイスで使用されます。派生クラスの1つに実装する必要があります。

仮想関数(実際にはメソッド)は、同様に宣言する関数であり、継承階層クラスの1つに実装する必要があります。

そのようなクラスの継承されたインスタンスは、実装しない限り、より低い階層のクラスでも実装を継承します。

1
Sagi Berco

一般的なオブジェクト指向の視点から:

抽象メソッドについて :抽象クラスを実際に親クラスに入れたとき、あなたは子クラスに言っているのです。そしてあなたがそれを使いたいのなら、あなたはあなた自身のものを実装するべきです!

仮想関数について :あなたが親クラスに仮想メソッドを入れたとき、派生クラスに言っているのです。これが役に立つならあなたはそれを使うだけです。そうでない場合は、これをオーバーライドしてコードを実装してください。たとえあなたがコード内で私の実装を使用することも可能です。

これは一般的なオブジェクト指向のこの2つの概念間の相違についてのある哲学です

1

答えは何度も提供されてきましたが、それぞれをいつ使用するかについての質問は設計時の決定です。一般的なメソッド定義を別々のインタフェースにまとめ、それらを適切な抽象化レベルでクラスにまとめることを試みるのは良い習慣だと思います。一連の簡潔なインタフェースを実装する非抽象クラスを定義するのが最善である場合がある場合、抽象および仮想メソッド定義の共通のセットをクラスにダンプすると、クラスが識別できなくなります。いつものように、それはあなたのアプリケーション特有のニーズに最も適しているものに依存します。

1
ComeIn

C#には仮想クラスと呼ばれるものは何もありません。

機能について

  1. 抽象関数は署名のみを持ち、ドライブクラスは機能を上書きするべきです。
  2. 仮想機能は、ドライブクラスが必要に応じてそれをオーバーライドするかしないかの機能の一部を保持します

あなたはあなたの要求で決めることができます。

C++の背景からは、C#virtualはC++ virtualに対応し、C#abstractメソッドはC++ pure virtual functionに対応します。

0
Yituo

ここでは、これが非常に基本的なレベルでインターフェース、抽象クラス、および通常のクラスの動作を確認するためのかなり具体的な例になることを願って、いくつかのサンプルコードを書いています。デモとして使用したい場合は、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(){
    //
    //    }
    }
}
0
U.Savas

抽象関数またはメソッド はクラスによって公開される公開された「操作の名前」であり、その目的は、抽象クラスとともに、主に、オブジェクトが実装しなければならない構造に対する制約の形式を提供することです。 

実際、その抽象クラスから継承するクラスはこのメソッドに実装を与えなければなりません。一般的にコンパイラはそうでないときにエラーを発生させます。

抽象クラスとメソッドを使用することは、クラスを設計するときに実装の詳細に焦点を当てることで、実装と密接に関連するため、依存関係を作成し、それらの間で連携するクラス間のカップリングを回避するためです。

仮想関数またはメソッド は単にクラスのパブリックビヘイビアをモデル化するメソッドですが、子クラスには特定の拡張機能を実装する必要があると考えられるため、継承チェーンで自由に変更できます。その行動のために。

どちらもオブジェクト指向パラダイムでは 多態性 の形を表します。 

良い継承モデルをサポートするために抽象メソッドと仮想関数を一緒に使うことができます。

私達は私達のソリューションの主要オブジェクトの良い抽象構造を設計し、それからさらに特殊化しやすいものを見つけることによって基本的な実装を作成します。そしてこれらを仮想にします。最後に基本的な実装を特殊化します。

0
Ciro Corvino