2011-06-17 7 views
1

私は、メンバ関数を呼び出す必要があります(継承は物事を簡単にするためにほとんどの場所で使用されています)が、パフォーマンスで非バーチャルディスパッチを使用して強制的に呼び出したいそのような場所では、正確な型はコンパイル時に知られています。私はパフォーマンス上の理由から、仮想コールのパフォーマンスが悪いプラットフォームでこれを行います。ほとんどの機能では、仮想関数のオーバーヘッドは問題ありませんが、いくつかの点ではそうではありません。私は仮想と非仮想の両方としてすべての機能を複製しないようにしたいと思います。テンプレート内で非仮想ディスパッチを使用する

例:

template <typename Derived> 
class Base { 
public: 
    virtual ~Base() {} 
    void foo() { Derived::func_in_derived(); } 
}; 
class Derived : public Base<Derived> { 
public: 
    void func_in_derived() {} 
}; 
+1

コンパイラはこのようなケースを検出し、自動的に静的ディスパッチを使用する必要があります。 –

+1

@dark_charlie:もっとも簡単な場合のみです。複雑ではないケースは、リンク時やその他のグローバル最適化手法でカバーする必要があります。これは、コンパイラではあまり普及していないか、非常に若いです。ポインタ/参照を予測することが難しい仮想関数を呼び出す場合コンパイラは静的ディスパッチを行います。 –

+0

非実装の 'Implementation :: DoImpl()'に関して 'Implementation :: Do()'を実装して、パフォーマンス重視の場所で後者を呼び出すことができます。 –

答えて

2

あなたはあなたのようにそれを行うことができ、正確な種類を知っている場合:

class Interface 
{ 
    public: 
    virtual void Do(){} 
}; 

class Implementation: public Interface 
{ 
    public: 
    virtual void Do(){} 
}; 


void DoIt(Interface &func) 
{ 
    func.Do(); 
}; 

int main() 
{ 
    Implementation a; 
    DoIt(a); 
    // can DoIt be constructed as a template to avoid virtual dispatch? 
    return 0; 
} 
+0

私はそれを少し変更しました。それは私にとってより良いようです。しばしば私はすでに正確な型を持っており、キャストする必要はありません:template void DoIt(Implementation&func) { func.Implementation :: Do(); };必要に応じてDo(static_cast (func))として使用できます。 – Suma

+0

..そして私の典型的なケースでは、コンパイラは正確な型を知っているので、単純にDo(func)として使用されます。 – Suma

1

私はあなたがあなたのstatic polymorphismを可能に不思議経常テンプレートパターン(CRTP)を探していると思います:

template <typename StaticType> 
void DoIt(Interface &func) 
{ 
    static_cast<StaticType&>(func).StaticType::Do(); 
}; 

必要なタイプに手動でダウンキャストする必要がある場合(static_castの場合はと入力してください。と入力してください)。次に、メソッド呼び出しを修飾し、動的ディスパッチを無効にする必要があります。

struct DerivedType : Interface { 
    virtual void Do() { std::cout << "Derived::Do" << std::endl; } 
}; 
struct MostDerived : DerivedType { 
    virtual void Do() { std::cout << "MostDerived::Do" << std::endl; } 
}; 
void processDerived(Interface & iface) { 
    DoIt<DerivedType>(iface); 
} 
int main() { 
    MostDerived obj; 
    DoIt<Derived>(obj); // Will call Derived::Do 
} 

修飾名を使用すると、動的ディスパッチを無効にすることに注意してください、そしてそれはそれは、オブジェクトの実行時の型に、しかし、あなたが呼び出すためにそれを伝えるタイプに派遣されていないことを意味します。

+0

正確ではありませんが、あなたは正しいです。技術は最後に似ています。しかし、作業を実行する関数は無関係であり、インタフェース/実装の基本クラスにしたくありません。 – Suma

関連する問題