2012-03-28 4 views
18

動的/静的多型は、アプリケーションの設計と要件によって異なることを理解しています。しかし、可能であれば、常に静的多型を動的に選択することをお勧めしますか?まだテンプレートの形式のインターフェイスを提供しながら、何のvtableのルックアップオーバーヘッドを:CRTPを使用していない静的ポリモーフィズムを実装DyamicとC++の静的多型:これは好ましいですか?

  1. :特に、私は反対をお勧めしているように見えるどちらも、私のアプリケーションでは、次の2設計上の選択を見ることができますベースクラス。しかし、動的な多型

  2. 危険で正しいクラス/メソッドにアクセスするスイッチとはstatic_castのロットを使用して:アクセサ/ミューテータ

    ようにも些細な機能のためのルックアップコストを関連付け、インターフェイス(純粋仮想クラス)を実装

私のアプリケーションは非常にタイムクリティカルなので、静的な多形性を優先します。しかし、あまりにも多くのstatic_castを使用することは、設計が貧弱であることを示すものであり、遅延を招くことなく回避する方法を知る必要があります。

EDIT:洞察のためにありがとう。具体的なケースを考えてみましょう。どれが良いアプローチですか?

class IMessage_Type_1 
{ 
    virtual long getQuantity() =0; 
... 
} 
class Message_Type_1_Impl: public IMessage_Type_1 
{ 
    long getQuantity() { return _qty;} 
... 
} 

OR

template <class T> 
class TMessage_Type_1 
{ 
    long getQuantity() { return static_cast<T*>(this)->getQuantity(); } 
... 
} 
class Message_Type_1_Impl: public TMessage_Type_1<Message_Type_1_Impl> 
{ 
    long getQuantity() { return _qty; } 
... 
} 

注意が各クラスにはいくつかのミューテータ/アクセサがあり、私は自分のアプリケーションのインターフェイスを指定する必要がないということ。静的多型では、メッセージタイプを取得するために1回だけ切り替わります。しかし、動的な多態性では、私はそれぞれのメソッド呼び出しに仮想関数を使用しています。静的なポリを使用することはできませんか?私はCRTPのstatic_castはかなり安全で、パフォーマンスのペナルティは(コンパイル時間バインド)はないと思いますか?

+4

switch-case構造体は、vtableを使用するのと同じ複雑さを持ちます。 – user877329

+0

静的多型を使用するときにstatic_castとスイッチがたくさんあると思われる理由がわかりません - いくつかのサンプルコードを表示できますか? –

+1

@MichaelAnderson:静的多型を必要とする状況で静的多型を使用しようとすると、そのようになります。そのような場合は、動的ポリモーフィズムを再作成しようとするのではなく、使用することがほぼ確実です。 –

答えて

8

スイッチはアドレスへのジャンプは表によるアップを見になりoptimized- -afterジャンプのシーケンス以外の何ものでもありません。仮想関数呼び出しとまったく同じです。

あなたは種類に応じてジャンプする必要がある場合は、最初のタイプを選択する必要があります。コンパイル時に選択できない場合は(基本的に入力に依存するため)、必ず&ジャンプの2つの操作を実行する必要があります。 構文ツールあなたが選択するのはパフォーマンスを変えるものではありません。実際に

あなたは V-テーブルを再発明あります。呼び出されたメソッドは、コンパイラによってインライン化することができる場合

+0

私はスイッチケースが基本的にvtableであることに同意します。しかし、動的多態性では、EVERYメソッドに仮想を使用しますが、静的では派生型を取得するために一度切り替えてキャストする必要があり、その後は間接指定はありません。質問に例を追加しました。これを実装するより良い方法はありますか? – vid

+0

@vid:呼び出し元が派生型について知ることが許可されている場合、ポリモフィズムの目的は何ですか? この場合、呼び出し元は、抽象クラスやインターフェイスなどを使わずに直接派生クラスとやりとりすることができます。 ここで多相性と継承の両方が重複しているようです。 発信者が派生型について知ることを許可されていない場合は、 型キャストおよびメソッドのディスパッチは、基本クラス内の各呼び出しで実行する必要があります。 vtableはそのようなディスパッチのための最適なソリューションです。 CRPTは、ベースから派生クラスへの呼び出しを最適化するための適切なツールです(唯一) – user396672

+0

よろしくお願いします。私がしようとしていたのは、CRTPを使ってインターフェイスを指定することでした。そのため、他の開発者がライブラリを拡張したい場合、CRTPを使って基本クラスを継承し、メソッドの実装に失敗するとコンパイルエラーがスローされます。純粋な仮想基本クラスと同じロジックですが、vtableオーバーヘッドはありません。これをより適切に実装していると考えることができるイディオムがありますか? – vid

6

純粋なテンプレートベースの多型に関連する設計上の問題があります。見た目の仮想基底クラスは、派生クラスから期待されるものをかなり良いアイデアにしますが、これはテンプレートの重いデザインではますます難しくなります。ブーストライブラリの1つを使用している間に構文エラーを導入することで、簡単にそのことを実証できます。

一方、仮想関数を使用する場合、パフォーマンスの問題が懸念されます。これが問題になることを証明することははるかに困難です。

IMHOこれは質問ではありません。他に指示があるまで、仮想機能に固執する。仮想関数の呼び出しは、ほとんどの人が思うよりはるかに高速です(動的にリンクされたライブラリから関数を呼び出すことによって間接的な層が追加されます)。

コードを読みやすく(一般的なアルゴリズム)、テンプレートの設計を考慮しているのは、仮想関数(数値アルゴリズム)が遅いことが知られているほとんどのケースの1つを使用しているか、ボトルネック。

+0

ありがとう@ebo。私は私のアプリケーションでボトルネックとして仮想関数をindetify、オーバーヘッドを明確にするために質問を編集 – vid

14

静的および動的多型は異なる 問題を解決するように設計されているため、両方が適切な場合はほとんどありません。このような場合、 では、動的多型性により、より柔軟な設計が容易になります。しかし、ほとんどの場合、他の理由で、選択は 明らかです。

二つのうちの一つ大まかな分類:仮想関数は、共通のインターフェイスのために異なる 実装を可能にします。テンプレートは共通の実装に異なる インターフェイスを許可します。

+0

'仮想関数は、共通のインタフェースに対して異なる実装を可能にします。テンプレートは共通のインプリメンテーションのための異なるインターフェースを可能にします」これは実際には意味をなさない。静的ポリモーフィズムは、実際には2つの異なるクラスが独自の実装を作成することを可能にしますが、メソッドは同じ名前を持ち、どちらの場合も基本クラスから呼び出されます。 – johnbakers

+1

@Fellowshee最も一般的な用途では、テンプレートクラスは異なるインタフェースを提供しますが、実装タイプごとに同じインプリメンテーションを提供します。 'std :: vector 'は 'push_back(double)'関数を提供します。 'std :: vector 'は 'push_back(int)'を提供します。異なるインターフェース。同じ実装。仮想 'push_back(double)'からの継承は、異なる実装を可能にしますが、異なるインタフェースを許可しません。 –

1

静的polimorphismは重要な利点を提供することができます。 は例えば、仮想メソッドは次のように見える場合:

protected: 
virtual bool is_my_class_fast_enough() override {return true;} 

、静的polimophismが好ましい方法(そうでない場合は、この方法は、正直に言うと偽:)を返す必要がありますする必要があります。 (ほとんどの場合)

「真の」仮想呼び出しがインライン化することはできません。 (このようvtableの呼び出しで追加の間接など)

他の違いは

無視されている[EDIT]

しかし、呼び出し側が知っているべきではない場合本当には、ランタイムポリモーフィズム を(必要な場合は、メソッドの実装と、したがって、メソッドは、呼び出し側の側にインライン化することはできません) vtable(Emilio Garavagliaが述べたように)を改革しないでください。

関連する問題