2011-06-17 40 views
1

我想調用一個虛擬的成員函數(在大多數地方使用繼承來保持簡單),但我想強制使用非虛擬調度來調用它,有時在性能關鍵的地方,並在這些地方確切的類型是已知的編譯時間。出於性能原因,我在虛擬通話性能不佳的平臺上這樣做。對於大多數功能而言,虛擬功能的開銷很好,但有一些功能不是。我想避免重複虛擬和非虛擬的所有功能。在模板中使用非虛擬調度

例子:

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; 
} 
+1

編譯器應該檢測到這種情況並自動使用靜態分派。 –

+1

@dark_charlie:只在最平凡的情況下。非平凡的情況必須被鏈接時間或其他全局優化技術所覆蓋,這些技術在編譯器中並不太普及或者非常年輕,並且在通過難以預測指針/引用來調用虛擬函數的情況下,幾乎沒有編譯器會靜態分派。 –

+0

您可以通過非虛擬的'Implementation :: DoImpl()'實現'Implementation :: Do()',並在性能關鍵的地方調用後者。 –

回答

2

如果你知道確切的類型,你可以做到這一點的:

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

太好了。我修改了一下,因爲它對我來說似乎更好。通常我已經有了確切的類型,並且不需要進行轉換:template void DoIt(Implementation&func) func.Implementation :: Do(); };可以在需要時用作Do(static_cast (func))。 – Suma

+0

..在我的典型情況下,編譯器已經知道確切的類型,它將被簡單地用作Do(func)。 – Suma

1

我認爲你正在尋找奇異遞歸模板模式(CRTP),使您static polymorphism

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

不完全是這樣,但你是正確的,這項技術最終會是類似的。執行這個工作的函數是一種不相關的,我不想讓它成爲接口/實現的基類。 – Suma