先來分析一下int * (*ptr)()
1.由於小括號的運算級比較高,結合方法又是自左向右,所以先運算(*ptr),表明定義了一個指針ptr
2.接下來再運算最右邊的小括號(),表明是一個函數
3.接下平再運算* (*ptr)(),表明函數的返回值是一個指針
4.那麼int * (*ptr)()表明定義了一個指針變量ptr,它指向一個沒有參數,並且返回值是一個整型指針的函數。
這就叫做指向函數的指針,雖然以前聽人說大多都是在回調函數中用,但是一直感覺和普通函數每什麼區別,今天看了一個博客算是多多少收懂了一下,下面的博文有點長,不過如果你看懂了相信收貨一定會不小的(起碼我懂了回調函數到底是怎麼一回事~~)。
博文原址http://blog.csdn.net/hzyong_c/article/details/7464202
首先,先介紹一下指向函數的指針
函數指針在C/C++編程中使用的廣泛性,而對於一些初級編程者來說對函數指針的使用或許有些迷惑,而一旦在適當的時候使用了函數指針,會使代碼簡潔有力。本篇介紹的是函數指針的基礎部分,函數指針複雜的應用將在下一篇介紹。
一 指向普通函數的指針
先來看一個函數:
-
int Sum(int a, int b)
-
{
-
return a + b;
-
}
這個函數,調用方式可以如
Sum(1, 2);
若要表示函數的指針,可以用&Sum,也可以將Sum前邊的地址操作符&去掉,對於普通函數,地址操作符&是可選的。
下面介紹函數指針變量和函數指針類型:
1. 函數指針變量
-
int (*FnName)(int, int);
-
FnName = ∑
-
(*FnName)(3, 5);
第1行聲明瞭一個函數指針變量,如果有疑問,可以將FnName理解爲一個新定義的變量。函數指針變量的聲明格式:
返回類型(*函數指針變量)(參數列表);
第2行將Sum函數指針賦給它,注意,只有兩個函數指針參數類型,返回值類型完全相同纔可以賦值,注意修飾符const,&等不同也會導致賦值失敗。
第3行是調用,調用格式:
(*函數指針變量)(實參列表);
2. 函數指針類型
前面介紹了函數指針變量的聲明,那麼函數指針類型如何聲明呢?
在函數指針聲明前面加個typedef就成了函數指針類型定義。
-
typedef int (*FnType)(int, int);
-
FnType fb = ∑
-
(*fb)(3, 5);
第1行聲明函數指針的類型,FnType便是新聲明的類型,它是函數指針的類型。
第2行定義一個FnType類型的變量,並將Sum函數地址賦值給它。
第3行是函數調用。
前面已經瞭解了函數指針的變量和類型,看下面的代碼加深下理解:
-
int Sum(int a, int b)
-
{
-
return a + b;
-
}
-
-
typedef int (*FnType)(int, int);
-
int Fun1(FnType ft, int x, int y)
-
{
-
return (*ft)(x, y);
-
}
-
-
int Fun2(int (*fn)(int, int), int x, int y)
-
{
-
return (*fn)(x, y);
-
}
-
-
int main()
-
{
-
cout << Fun1(&Sum, 2, 3) << " ";
-
cout << Fun2(&Sum, 3, 4) << "\n";
-
return 0;
-
}
關於普通函數指針的學習就到這裏吧,簡單吧:),下面就來學習類的成員函數的指針。
二 指向類成員函數的指針
先看下面這個類:
-
class Num
-
{
-
public:
-
Num(){n_ = 0;}
-
void Inc(int n);
-
void Dec(int n);
-
static int Sub(int a, int b);
-
private:
-
long n_;
-
};
這個類中有普通成員函數,也有靜態成員函數,無論哪種函數,函數指針表示方式都是:
&類名::函數名
如Num類三個成員函數的指針分別是:
&Num::Inc;
&Num::Dec;
&Num::Sub;
1. 指向普通成員函數的指針
聲明一個指向類成員函數的指針時需要用到::*符號,左邊是類名,右邊是成員函數指針名:
返回類型 類名::*成員函數指針(參數列表);
調用的時候要用到.*或->*,左邊是類對象的引用或指針,右邊是成員函數指針:
(對象名.* 成員函數指針)(實參);
或
(對象指針->* 成員函數指針)(實參);
代碼示例:
-
int main()
-
{
-
Num obj;
-
void (Num::*mf)(int);
-
mf = &Num::Inc;
-
(obj.*mf)(1);
-
-
-
typedef void (Num::*mt)(int);
-
mt fn = &Num::Dec;
-
(obj.*fn)(2);
-
-
return 0;
-
}
注意上面,Sub是靜態成員函數,其指針聲明跟非靜態成員函數不一樣,下面來看靜態成員函數的指針。
2. 指向靜態函數的指針
-
int (*smf)(int a, int b);
-
smf = &Num::Sub;
-
cout << (*smf)(6, 7);
可以看到,靜態成員函數指針變量、類型聲明與普通函數一致。
3. 指向虛函數的指針
先上代碼:
-
class Base{
-
public:
-
virtual void F() const
-
{
-
cout << "I am the Base\n";
-
}
-
-
typedef void (Base::*FnPtr)() const;
-
};
-
-
class Derived : public Base{
-
public:
-
virtual void F() const
-
{
-
cout << "I am the Derived\n";
-
}
-
};
-
-
int main()
-
{
-
Base::FnPtr fp = &Base::F;
-
Base base;
-
(base.*fp)();
-
Derived derived;
-
(derived.*fp)();
-
-
return 0;
-
}
輸出結果:
I am theBase
I am theDerived
可見,虛函數的指針調用結果跟直接調用虛函數效果一樣,虛函數的指針指向的函數地址是對象動態綁定的函數地址。
接下來,介紹一下函數指針在回調函數的應用
模板類,該類擁有2個成員,一個是對象指針,一個是成員函數,成員函數必須無參,無返回值。
-
struct CallbackAction {
-
virtual void Execute() = 0;
-
virtual ~CallbackAction() {}
-
};
-
-
template <class OBJECT, class METHOD>
-
struct CallbackMethodAction : public CallbackAction {
-
OBJECT *object;
-
METHOD method;
-
-
void Execute() { (object->*method)(); }
-
-
CallbackMethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}
-
};
爲使用起來方便,進一步封裝。
-
class Callback{
-
public:
-
explicit Callback(CallbackAction *newaction) { action = newaction; }
-
Callback() { action = NULL; }
-
~Callback();
-
Callback(const Callback& c);
-
Callback& operator=(const Callback& c);
-
void Execute() const { if(action) action->Execute(); }
-
void operator()() const { Execute(); }
//這裏重寫了()
-
-
private:
-
CallbackAction *action;
-
};
-
-
Callback::Callback(const Callback& c)
-
{
-
action = c.action;
-
}
-
-
Callback::~Callback()
-
{
-
}
-
-
Callback& Callback::operator=(const Callback& c)
-
{
-
action = c.action;
-
return *this;
-
}
爲調用方便,再增加一個接口函數,注意,這裏進行了new操作,沒有delete,會造成內存泄露,本例沒有處理內存問題,解決這個問題,可以再Callback類裏添加計數器,管理指針。
-
template <class OBJECT, class METHOD>
-
Callback callback(OBJECT *object, void (METHOD::*method)()) {
-
return Callback(new CallbackMethodAction<OBJECT, void (METHOD::*)()>(object, method));
-
}
看一下如何應用
-
class Girl
-
{
-
public:
-
void Shopping()
-
{
-
cout << "I want to shopping" << endl;
-
WhenShopping();
-
}
-
-
Callback WhenShopping;
-
};
-
-
class Boy
-
{
-
public:
-
void Bind(Girl* girl)
-
{
-
girl->WhenShopping = callback(this, &Boy::OnShopping);
//這裏就是指 //向函數的指針
-
}
-
-
private:
-
void OnShopping() {cout << "I know she is shopping" << endl;}
-
};
客戶端調用
-
void main()
-
{
-
Girl girl;
-
Boy boy;
-
boy.Bind(&girl); //這裏可以看出回調的端倪,其實回調是在綁定的時候把要響應的對象值賦給調用的對象,當調用對象遇到重載後的括號()就會執行響應的動作
-
-
girl.Shopping();
-
}
輸出結果:
I want to shopping
I know she is shopping
上面的的代碼只是個callback使用的雛形,沒有處理內存問題和由const修飾的參數問題,直接使用會有內存泄露。另外,如果需要帶參數的函數指針類型,需要再擴展。
//下面的我也沒看過了。。。。。。。。。。。。
下面是帶1個參數和帶2個參數的函數指針類型的應用,更多參數的函數指針這裏就不再展示了。
-
template <class P1>
-
struct Callback1Action {
-
virtual void Execute(P1 p1) = 0;
-
virtual ~Callback1Action() {}
-
};
-
-
template <class OBJECT, class METHOD, class P1>
-
struct Callback1MethodAction : public Callback1Action<P1> {
-
OBJECT *object;
-
METHOD method;
-
-
void Execute(P1 p1) { (object->*method)(p1); }
-
-
Callback1MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}
-
};
-
-
template <class P1>
-
class Callback1{
-
public:
-
explicit Callback1(Callback1Action <P1> *newaction) { action = newaction; }
-
Callback1() { action = NULL; }
-
~Callback1();
-
-
Callback1& operator=(const Callback1& c);
-
Callback1(const Callback1& c);
-
-
void Execute(P1 p1) const { if(action) action->Execute(p1); }
-
void operator()(P1 p1) const { Execute(p1); }
-
-
private:
-
Callback1Action<P1> *action;
-
};
-
-
template <class P1>
-
Callback1<P1>& Callback1<P1>::operator=(const Callback1& c)
-
{
-
action = c.action;
-
return *this;
-
}
-
-
template <class P1>
-
Callback1<P1>::Callback1(const Callback1& c)
-
{
-
action = c.action;
-
}
-
-
template <class P1>
-
Callback1<P1>::~Callback1()
-
{
-
}
-
-
-
template <class OBJECT, class METHOD, class P1>
-
Callback1<P1> callback(OBJECT *object, void (METHOD::*method)(P1 p1)) {
-
return Callback1<P1>(new Callback1MethodAction<OBJECT, void (METHOD::*)(P1 p1), P1>(object, method));
-
}
-
template <class P1, class P2>
-
struct Callback2Action {
-
virtual void Execute(P1 p1, P2 p2) = 0;
-
virtual ~Callback2Action() {}
-
};
-
-
template <class OBJECT, class METHOD, class P1, class P2>
-
struct Callback2MethodAction : public Callback2Action<P1, P2> {
-
OBJECT *object;
-
METHOD method;
-
-
void Execute(P1 p1, P2 p2) { (object->*method)(p1, p2); }
-
-
Callback2MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}
-
};
-
-
template <class P1, class P2>
-
class Callback2{
-
public:
-
explicit Callback2(Callback2Action <P1, P2> *newaction) { action = newaction; }
-
Callback2() { action = NULL; }
-
~Callback2();
-
-
Callback2& operator=(const Callback2& c);
-
Callback2(const Callback2& c);
-
-
void Execute(P1 p1, P2 p2) const { if(action) action->Execute(p1, p2); }
-
void operator()(P1 p1, P2 p2) const { Execute(p1, p2); }
-
-
private:
-
Callback2Action<P1, P2> *action;
-
};
-
-
template <class P1, class P2>
-
Callback2<P1, P2>& Callback2<P1, P2>::operator=(const Callback2& c)
-
{
-
action = c.action;
-
return *this;
-
}
-
-
template <class P1, class P2>
-
Callback2<P1, P2>::Callback2(const Callback2& c)
-
{
-
action = c.action;
-
}
-
-
template <class P1, class P2>
-
Callback2<P1, P2>::~Callback2()
-
{
-
}
-
-
template <class OBJECT, class METHOD, class P1, class P2>
-
Callback2<P1, P2> callback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2)) {
-
return Callback2<P1, P2>(new Callback2MethodAction<OBJECT, void (METHOD::*)(P1 p1, P2 p2), P1, P2>(object, method));
-
}
應用代碼
-
class Girl
-
{
-
public:
-
void Shopping()
-
{
-
cout << "I want to shopping" << endl;
-
WhenShopping();
-
-
WhenBuy("fruits");
-
-
WhenBuy("chocolate");
-
-
WhenPay(20, 16);
-
}
-
-
void Swimming()
-
{
-
cout << "I want to swimming" << endl;
-
WhenSwimming();
-
}
-
-
Callback WhenShopping;
-
Callback WhenSwimming;
-
Callback1<string> WhenBuy;
-
Callback2<int, int> WhenPay;
-
};
-
-
class Boy
-
{
-
public:
-
void Bind(Girl* girl)
-
{
-
girl->WhenShopping = callback(this, &Boy::OnShopping);
-
girl->WhenSwimming = callback(this, &Boy::OnSwimming);
-
girl->WhenBuy = callback(this, &Boy::OnBuy);
-
girl->WhenPay = callback(this, &Boy::OnPay);
-
}
-
-
private:
-
void OnShopping() {cout << "I know she is shopping" << endl;}
-
void OnSwimming() {cout << "I know she is swimming" << endl;}
-
void OnBuy(string thing) {cout << "She buy " << thing << endl;}
-
void OnPay(int a, int b) {cout << "She pay " << a << " " << b << endl;}
-
};