18

動的/静的ポリモーフィズムは、アプリケーションの設計と要件に依存することを理解しています。ただし、可能であれば、動的ではなく静的ポリモーフィズムを常に選択することをお勧めしますか?特に、私のアプリケーションでは次の2つの設計上の選択を見ることができますが、どちらも推奨されていないようです。

  1. CRTPを使用して静的ポリモーフィズムを実装します。テンプレート基本クラスの形式でインターフェイスを提供しながら、vtableルックアップのオーバーヘッドはありません。ただし、多くのスイッチとstatic_castを使用して、正しいクラス/メソッドにアクセスします。これは危険です。

  2. 動的ポリモーフィズム:インターフェース(純粋仮想クラス)を実装し、アクセサー/ミューテーターのような些細な関数でもルックアップコストを関連付けます

私のアプリケーションは非常にタイムクリティカルなので、静的ポリモーフィズムを支持しています。ただし、static_castの使用が多すぎることが設計が不十分であることを示しているかどうか、および遅延を発生させずにそれを回避する方法を知る必要があります。

編集:洞察に感謝します。特定のケースを取り上げると、これらのどれがより良いアプローチですか?

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

また

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; }
...
}

各クラスにはいくつかのミューテーター/アクセサーがあり、アプリケーションでインターフェースを指定する必要があることに注意してください。静的ポリモーフィズムでは、メッセージタイプを取得するために一度だけ切り替えます。ただし、動的ポリモーフィズムでは、各メソッド呼び出しに仮想関数を使用しています。それは静的ポリを使用する場合にはなりませんか?CRTPのstatic_castは非常に安全で、パフォーマンスの低下(コンパイル時の制限)はないと思いますか?

4

4 に答える 4

15

静的および動的ポリモーフィズムは、さまざまな問題を解決するように設計されているため、両方が適切な場合はめったにありません。このような場合、動的ポリモーフィズムにより、設計の管理がより柔軟で簡単になります。しかし、ほとんどの場合、他の理由から、選択は明白です。

2つの大まかな分類:仮想関数により、共通のインターフェースに対して異なる実装が可能になります。テンプレートを使用すると、一般的な実装でさまざまなインターフェイスを使用できます。

于 2012-03-28T12:20:08.407 に答える
9

スイッチは、最適化された後、テーブルによって検索されたアドレスへのジャンプになる一連のジャンプにすぎません。仮想関数呼び出しとまったく同じです。

タイプに応じてジャンプする必要がある場合は、最初にタイプを選択する必要があります。コンパイル時に選択を実行できない場合(基本的に入力に依存するため)、常に2つの操作(選択とジャンプ)を実行する必要があります。選択に使用する構文ツールは、同じように最適化するため、パフォーマンスは変わりません

実際、あなたはvテーブルを再発明しています。

于 2012-03-28T13:00:33.847 に答える
6

純粋にテンプレートベースのポリモーフィズムに関連する設計上の問題があります。見た目の仮想基本クラスは、派生クラスから何が期待されるかについてかなり良いアイデアを提供しますが、これは、高度にテンプレート化された設計でははるかに困難になります。Boostライブラリの1つを使用しているときに構文エラーを導入することで、それを簡単に示すことができます。

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

私見これは問題ではありません。特に明記されていない限り、仮想関数を使用してください。仮想関数呼び出しは、ほとんどの人が考えるよりもはるかに高速です(動的にリンクされたライブラリから関数を呼び出すと、間接参照のレイヤーも追加されます。誰もそれについて考えていないようです)。

テンプレートデザインを検討するのは、コードが読みやすくなる場合(一般的なアルゴリズム)、仮想関数で低速であることがわかっている数少ないケースの1つを使用する場合(数値アルゴリズム)、またはパフォーマンスのボトルネックとしてすでに特定されている場合のみです。

于 2012-03-28T12:11:11.833 に答える
2

呼び出されたメソッドがコンパイラーによってインライン化される場合、静的ポリモーフィズムは大きな利点を提供する可能性があります。たとえば、仮想メソッドが次のようになっている場合:

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

その場合、静的ポリモーフィズムが好ましい方法である必要があります(そうでない場合、メソッドは正直で、falseを返す必要があります:)。

「真の」仮想呼び出し(ほとんどの場合)はインライン化できません。

その他の違い(vtable呼び出しでの追加の間接参照など)は無視できます

[編集]

ただし、ランタイムポリモーフィズムが本当に必要な場合(呼び出し元がメソッドの実装を知らないため、呼び出し側でメソッドをインライン化できない場合)、vtableを再発明せず(Emilio Garavagliaが述べたように)、それを使用するだけです。 。

于 2012-03-28T14:44:37.580 に答える