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 意見:
張貼留言