2012-02-24 14 views
-3

タイトルに似ています。 新しいプログラマとして、私のプロジェクトの仕組みを知ることは非常に重要で、それを使うことの違いは何ですか?どの男が私に答えを与えることができます、ありがとう!抽象基本クラスのコールバック関数と仮想関数の使用の違いは何ですか?

+9

新しいプログラマとして、尋ねる前にgoogleにとって非常に重要です。 :) – ghostCoder

+0

すべての必要な答えは、グーグルで見つけることができます!私たちができるのは、リンクを提案することだけです。質問に答えない –

+0

私はあなたのために質問をreworded – CashCow

答えて

5

仮想関数はコールバックを提供する1つのメカニズムですが、それだけではありません。

コールバックの一般性は、パラメータ、メソッド、メソッドを呼び出すオブジェクト、渡す関数によって呼び出されるオブジェクト、またはその関数によって格納されるオブジェクトを渡すことですイベントが発生したときに後で呼び出されます。

このようなメカニズムを実装する1つの方法は、基本クラスから派生し、仮想関数を実装するオブジェクトへのポインタまたは参照を渡すことです。

もう1つの方法は、関数ポインタを渡すことです。

さらに、機能ポインタを持つオブジェクトを渡すことができます。これは、どのような追加機能があるかです。機能を高めるコンストラクタ(多くの場合、boost::bind)は巧みにそのようなオブジェクトを作成します。

C++ 11では、コールバックとして渡すために無名関数をオンザフライで構築することができます。これは通常ラムダと呼ばれます。

仮想関数をコールバックとして使用するメカニズムについてもう少し詳しく説明します。これは、行うには、かなりきちんとしたもののように見えることができます。

class Handler 
{ 
    public: 
    virtual ~Handler() {} 
    virtual void process(std::string const& message) = 0; 
}; 

void getMessage(Handler& handler) 
{ 
    std::string str = getAMessage(); 
    handler.process(str); 
} 

でも整然とハンドラをこのように構成することである。

class Handler 
{ 
    public: 
    virtual ~Handler() {} 
    void process(std::string const& message) 
    { 
     // can log or put in a breakpoint here on debugging 
     doProcess(message); 
    } 

    protected: // or private 
     virtual void doProcess(std::string const& message) = 0; 
}; 

ここでの利点は、にデバッグすることは容易であるということです。

Handlerオブジェクトのライフタイムを管理する必要がある場合、つまりコールバックが非同期に発生する場合は、より複雑になります。次に、両側が参照を保持するようにshared_ptr<Handler>を使用する必要があり、それが管理されます。

これを行うことで、通常のコールバック関数よりも大きな利点は、オブジェクトに余分な情報を保持できることです。コールバック自体は固定数のパラメータしか取ることができません。コールバックでは、しばしばvoid *を使用して余分な情報を取得するために何かにキャストする必要があります。このクラスを使用すると、メンバ変数にその情報を保持することができます。また、メソッドが呼び出された後にクラスが状態を保持できるようになります。

しかし、このような抽象クラスを作成してそこからクラスを派生させなければならないということです。

これは、ブースト機能とバインドが非常に便利になる場所です。本当に必要なのは、呼び出される特定のシグネチャを持つ関数で、このコールバックを処理するために余分なクラスを作成する必要はありません。したがって、この状況をはるかに迅速にプログラムすることができます。

しかし、残念ながら欠点もあります。ブースト機能は、デバッグがはるかに難しいです。あなたはブースト機能自体の寿命を管理することに注意する必要はありませんが、あなたはそれに渡すパラメータに注意する必要があります。それはあなたがそれらを渡す方法だけを盲目的に保管します。リファレンスホルダー(boost::ref)としてローカル変数への参照を渡すと、実際にこの参照が格納され、関数が呼び出される前にスコープから外れてしまうと、このバグを見つけるのが困難になることがあります。

これにもかかわらず、私はライブラリの機能を利用することをお勧めします(標準ではstd :: functionとstd :: bindがありますが、lambdaがコンパイラの間で標準になるときは、 )。

2

コールバック関数は、プログラムの他の部分から参照されるものです。オブジェクトへのポインタをどのように渡すことができるか考えてください。同じことは関数で行うことができます。しかし、これは初心者のプログラマーにとって挑戦的な話題と考えることができます。

仮想関数は、子クラスによって実装できる関数を指します。期間polymorphismを読んでください。

1

コールバック関数は、別の場所で実行される可能性のあるパラメータとして渡す関数です。

仮想関数は、C++の多態性のビルディングブロックの1つです。つまり、このメソッドを基本クラスのオブジェクトで呼び出すと、継承チェーンの最上位の派生クラスから同じメソッドが呼び出されます。

1

コールバック関数はトレースするのが難しいですが、時には非常に便利です。特にライブラリを設計しているとき。コールバック関数は、ユーザーに関数名を与えるように要求するもので、特定の条件下でその関数を呼び出すことができます。

void cbfunc() 
{ 
    printf("called"); 
} 

int main() 
{ 
    /* function pointer */ 
    void (*callback)(void); 

    /* point to your callback function */ 
    callback=(void *)cbfunc; 

    /* perform callback */ 
    callback(); 

    return 0; 
} 

virual関数は、関数をオーバーライドすることによって多型を達成するために使用されることを意味します。

2

コールバック関数は、制御の反転(重要なデザインパターン)を実装しています。仮想関数は多態性(プログラミングパラダイム)を実装します。基本的には、コードは2つの異なる角度から見えるという意味で無関係です。制御の反転を実装する1つの方法は、仮想関数が効果的にコールバック関数になる抽象基本クラスを使用する方法です。しかし、用語コールバック関数を聞くときのほとんどの場合、抽象基本クラスと仮想関数を使用できないC言語で定義されたAPIに関するものです。そのような場合は、フリー関数(通常extern "C")が必要です。ほとんどの場合、この関数はvoid*引数を受け取ってデータを渡すことができます。

+0

extern "C"は関数のプロトタイプではなく名前のマングリングと関係があります。それ以外はあなたの答えはかなり良いです。 – CashCow

+0

@CashCow 'extern" C "'は、名前のマングリングが一部に過ぎない呼び出し規約を指定します。関数が 'extern" C "'であるかどうかは、その型の一部です。コンパイラが 'extern" C++関数を引数として 'extern" C "'を必要とする関数に渡すことを許可していれば、それは標準に準拠していません。 'pthread_create'のような関数は、渡された関数を' extern "C"(少なくとも標準を適用するコンパイラで)必要とします。 –

関連する問題