2012-02-11 40 views
0

替代虛函數我有一個基類中定義的昂貴功能,它依賴於低電平信息從它的派生類:如果我正確理解事物模板如在C++

class BaseClass{ 
... 
// Defined in derived class 
virtual int low_level(int)=0; 

// Expensive function depending on the pure virtual function 
void myExpensiveFunction(){ 
    for(...){ 
    for(...){ 
     for(...){ 
     ... = low_level(...); 
     ... 
     } 
    } 
    } 
} 
}; 

class DerivedClass : public BaseClass{ 
    // A very cheap operation that can be inlined: 
    inline virtual int low_level(int i){ 
    return a[i]; 
    } 

    // Calling the base class function 
    void test(){ 
    myExpensiveFunction(); 
    } 
}; 

,事實低級函數是虛擬的,可以防止它在上面的代碼中被內聯。現在,我在想一個辦法來解決這個問題,並在下述溶液,想到這裏我傳遞一個指向派生類的成員函數作爲模板參數:

class BaseClass{ 
... 
// The function is now templated by the derived function: 
template<typename D, int (D::*low_level)(int)> 
void myExpensiveFunction(){ 
    for(...){ 
    for(...){ 
     for(...){ 
     ... = static_cast<D*>(this)->low_level(...); 
     ... 
     } 
    } 
    } 
} 
}; 

class DerivedClass : public BaseClass{ 
    // A very cheap operation that can be inlined: 
    inline int low_level(int i){ 
    return a[i]; 
    } 

    // Calling the base class function 
    void test(){ 
    myExpensiveFunction<DerivedClass,&DerivedClass::low_level>(); 
    } 
}; 

這是否戰略意義?我想象當在派生類中擴展昂貴的基類函數時,低級操作將被內聯。

我測試過實現它,它編譯和工作,但我沒有看到任何明顯的性能差異。

親切的問候, 喬爾

+0

*這個策略是否有意義?*否 – 2012-02-11 12:24:33

+0

*我想當在派生類中擴展昂貴的基類函數時,將會內聯低級操作。*您是否檢查了程序集? – jpalecek 2012-02-11 12:30:14

+0

在昂貴的功能中獲得對「a」的引用是否是一種選擇? – 2012-02-11 12:44:39

回答

4

傳遞的功能,你想用一個指針成員基類調用並沒有真正改善使用虛擬函數。事實上,我預計它會讓情況變得更糟。另一種方法是使用函數對象與inline函數調用操作符並調用它。 「正常」方法是反轉類層次結構並使用Curiously Recurring Template Pattern:這個想法是創建一個將從其模板參數派生的模板。期望模板參數提供定製點,例如功能low_level

+0

我對Curiously recurring template pattern idiom不知道。這絕對是更優雅,所以我會用它來代替。雖然我仍然不明白爲什麼我的解決方案與傳遞成員函數模板不起作用。我的意思是,編譯器擁有所需的所有信息來嵌入函數。 – Joel 2012-02-11 13:33:13

+0

我並不是說它不起作用。過去我只是嘗試了類似的東西,並測量了它的效果,而且他們往往不工作。爲了找出最好的方法,你顯然希望衡量性能。另外,您可能需要查看其他地方所建議的生成方式:您不需要了解彙編程序,但是如果事件是內聯的,您通常可以識別。 ...你可能會先看一下這個簡化的設置。 – 2012-02-11 17:30:53

+0

好的。無論如何,「奇怪的反覆出現的模板模式」習語很好,所以我會堅持。非常感謝!! – Joel 2012-02-11 18:00:37

2

根據不同的情況,你也可以嘗試以避免繼承和做這樣的事情,而不是:

template<typename LL> 
class HighLevel { 
    LL lowLevel; 

    public: 

    HighLevel(LL const &ll) : lowLevel(ll) { } 

    void myExpensiveFunction() { 
     for(...) { 
     for(...) { 
      for(...) { 
      ... = lowLevel.low_level(...); 
      ... 
      } 
     } 
     } 
    } 
}; 

class LowLevel { 
    public: 
    inline int low_level(int i) { // note: not virtual 
     return a[i]; 
    } 
}; 

使用,如:

HighLevel<LowLevel> hl; 
hl.myExpensiveFunction(); 

如果你不想不同類型的您可以從抽象的非模板class HighLevelBase中導出所有這些對象,並在模板中顯示virtual void myExpensiveFunction() = 0。我不能沒有更多的信息,但我發現C++通常提供比繼承更好的工具來解決特定的問題。

+1

不確定這裏指針的用途是什麼。只需傳遞一個普通(函數)對象。 – 2012-02-11 12:57:48

+0

對,我的情況確實需要額外的繼承。謝謝! – Joel 2012-02-11 13:49:29

+0

@KonradRudolph:你說得對。固定。 – Thomas 2012-02-11 14:37:56