CBase A; // 就像宣告函數一樣寫個簡單的例子:
A(); // 呼叫函數
#include <iostream> #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) class CBase { public: CBase() {} ~CBase() {} void operator() () { std::cout << "CBase!!!!!\n";} private: DISALLOW_COPY_AND_ASSIGN(CBase); }; int main() { CBase a; a(); return 0; }
另外從 http://www.newty.de/fpt/functor.html 挖出來的例子,用來說明跟一般函數的不同之處:
#include <iostream> #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) using namespace std; class TFunctor { public: // 我們來宣告兩種呼叫的方式,一個為operator(),另一種就是一般的Funtion Call virtual void operator()(const char* string) = 0; // call using operator virtual void Call(const char* string) = 0; // call using function }; template <class TClass> class TSpecificFunctor : public TFunctor { private: void (TClass::*fpt)(const char*); // 成員函數指標 TClass* pt2Object; // 物件指標 public: // 建構式引入物件指標以及函數指標,以來使用operator()和Call() // 第二個引入參數要為void function(const char*)的型式! TSpecificFunctor(TClass* _pt2Object, void(TClass::*_fpt)(const char*)) { pt2Object = _pt2Object; fpt = _fpt; }; // override operator "()" virtual void operator()(const char* string) { (*pt2Object.*fpt)(string); }; // override function "Call" virtual void Call(const char* string) { (*pt2Object.*fpt)(string); }; }; class TClassA { public: TClassA() {}; void Display(const char* text) { cout << text << endl; }; private: DISALLOW_COPY_AND_ASSIGN(TClassA); }; class TClassB { public: TClassB() {}; void Display(const char* text) { cout << text << endl; }; private: DISALLOW_COPY_AND_ASSIGN(TClassB); }; int main() { TClassA objA; TClassB objB; TSpecificFunctor<TClassA> specFuncA(&objA, &TClassA::Display); TSpecificFunctor<TClassB> specFuncB(&objB, &TClassB::Display); specFuncA.Call("TestA!"); // 用Function來呼叫 specFuncB("TestB!"); // 用()來呼叫 // 放入陣列裡 TFunctor* vTable[] = { &specFuncA, &specFuncB }; vTable[0]->Call("TClassA::Display called!"); // via function "Call" (*vTable[1])("TClassB::Display called!"); // via operator "()" return 0; }
仿函數有下列幾項優點:
- 仿函數可以不帶痕跡地傳遞上下文參數。而CallBack技術通常使用一個額外的void*參數傳遞。這也是多數人認為CallBack技術醜陋的原因。
- 更好的性能。
- func是inline函數,並且比較簡單,func呼叫最後被展開了,那麼其中對CallBack函數的呼叫也成為一普通函數呼叫(而不是通過函數指標的間接呼叫),並且如果這個CallBack函數很簡單,那麼也可能同時被展開。在這種情形下,CallBack函數與仿函數性能相同。
- func是非inline函數的話,或者比較複雜而無法展開(例如上面的std::sort,我們知道它是快速排序,函數因為存在遞回而無法展開)。此時CallBack函數作為一個函數指標傳入,他的程式碼也是無法被展開。而仿函數則不同。雖然func本身複雜不能展開,但是func函數中對仿函數的呼叫是編譯器編譯期間就可以確定並進行inline展開的。因此在這種情形下,仿函數比之於CallBack函數,有著更好的性能。並且,這種性能優勢有時是一種無可比擬的優勢(對於std::sort就是如此,因為元素比較的次數非常巨大,是否可以進行inline展開導致了一種雪崩效應)。
但是仿函數也並不能完全取代掉CallBack函數就是,有些地方還是需要用CallBack技術,不過能用仿函數就盡量使用吧!
部份文字來自於:維尼的蜂巢 與 http://www.newty.de/fpt/functor.html
0 意見:
張貼留言