1. 程式人生 > 其它 >C++ 函式指標及delegate的幾種方法

C++ 函式指標及delegate的幾種方法

技術標籤:delegate

delegate類似於函式指標。

函式指標是指向函式指標變數。 因此“函式指標”本身首先應是指標變數,只不過該指標變數指向函式。這正如用指標變數可指向整型變數、字元型、陣列一樣,這裡是指向函式。如前所述,C在編譯時,每一個函式都有一個入口地址,該入口地址就是函式指標所指向的地址。有了指向函式的指標變數後,可用該指標變數呼叫函式,就如同用指標變數可引用其他型別變數一樣,在這些概念上是大體一致的。函式指標有兩個用途:呼叫函式做函式的引數

方法

函式指標的宣告方法為:

返回值型別 ( *指標變數名) ([形參列表]);

注1:“返回值型別”說明函式的返回型別

,“(指標變數名 )”中的括號不能省,括號改變了運算子的優先順序。若省略整體則成為一個函式說明,說明了一個返回的資料型別是指標的函式,後面的“形參列表”表示指標變數指向的函式所帶的引數列表。例如:

int func(int x); /* 宣告一個函式 */

int (*f) (int x); /* 宣告一個函式指標 */

f=func; /* 將func函式的首地址賦給指標f */

或者使用下面的方法將函式地址賦給函式指標:

f = &func;

賦值時函式func不帶括號,也不帶引數,由於func代表函式的首地址,因此經過賦值以後,指標f就指向函式func(x)的程式碼的首地址

注2:函式括號中的

形參可有可無,視情況而定

下面的程式說明了函式指標呼叫函式的方法:

例一、

#include<stdio.h>
intmax(intx,inty){return(x>y?x:y);}
intmain()
{
int(*ptr)(int,int);
inta,b,c;
ptr=max;
scanf("%d%d",&a,&b);
c=(*ptr)(a,b);
printf("a=%d,b=%d,max=%d",a,b,c);
return0;
}

不過,在某些編譯器中這是不能通過的。這個例子的補充如下。ptr是指向函式的指標變數

,所以可把函式max()賦給ptr作為ptr的值,即把max()的入口地址賦給ptr,以後就可以用ptr來呼叫該函式,實際上ptr和max都指向同一個入口地址,不同就是ptr是一個指標變數,不像函式名稱那樣是死的,它可以指向任何函式,就看你想怎麼做了。在程式中把哪個函式的地址賦給它,它就指向哪個函式。而後用指標變數呼叫它,因此可以先後指向不同的函式。不過注意,指向函式的指標變數沒有++和--運算,用時要小心。

應該是這樣的:

1.定義函式指標型別:

typedef int (*fun_ptr)(int,int);

2.宣告變數,賦值:

fun_ptr max_func=max;

也就是說,賦給函式指標的函式應該和函式指標所指的函式原型是一致的。

例二、

#include<stdio.h>
voidFileFunc()
{
    printf("FileFunc\n");
}
voidEditFunc()
{
    printf("EditFunc\n");
}
voidmain()
{
    typedefvoid(*funcp)();
    funcppfun=FileFunc;
    pfun();
    pfun=EditFunc;
    pfun();
}

對比區別

指標函式函式指標的區別:

1,這兩個概念都是簡稱,指標函式是指返回值是指標的函式,即本質是一個函式。我們知道函式都有返回型別(如果不返回值,則為無值型),只不過指標函式返回型別是某一型別的指標。

其定義格式如下所示:

返回型別識別符號*函式名稱(形式引數表)

{函式體}

返回型別可以是任何基本型別和複合型別。返回指標的函式的用途十分廣泛。事實上,每一個函式,即使它不帶有返回某種型別的指標,它本身都有一個入口地址,該地址相當於一個指標。比如函式返回一個整型值,實際上也相當於返回一個指標變數的值,不過這時的變數是函式本身而已,而整個函式相當於一個“變數”。例如下面一個返回指標函式的例子:

//指標函式是指返回值是指標的函式,即本質是一個函式:
#include<iostream>
usingnamespacestd;
float*find(float(*p)[4],intm);//查詢序號為m的學生的四門課程的成績
intmain()
{
    floatscore[][4]={{50,51,52,55},{70,70,40,80},{77,99,88,67}};//定義成績陣列,第一維    可以為變數
    float*pf=NULL;//定義一個指標時一定要初始化
    inti,m;
    cout<<"請輸入您想查詢的學生的序號:";
    cin>>m;
    pf=find(score,m);//返回為一維陣列指標,指向一個學生成績
    for(i=0;i<4;i++)
        cout<<*(pf+i)<<"";
        cout<<endl;
        return0;
    }
}
float*find(float(*p)[4],intm)
{
    float*pf=NULL;
    pf=*(p+m);//p是指向二維陣列的指標,加*取一維陣列的指標
    returnpf;
}

指標陣列學生學號從0號算起,函式find()被定義為指標函式,其形參pointer是指標指向包含4個元素的一維陣列指標變數。pf是一個指標變數,它指向浮點型變數。main()函式中呼叫find()函式,將score陣列的首地址傳給pointer.

定義

關於函式指標陣列的定義方法,有兩種:一種是標準的方法;一種是矇騙法。

第一種,標準方法:

{

分析:函式指標陣列是一個其元素是函式指標的陣列。那麼也就是說,此資料結構是一個數組,且其元素是一個指向函式入口地址的指標。

根據分析:首先說明是一個數組:陣列名[]

其次,要說明其元素的資料型別指標:*陣列名[].

再次,要明確這每一個數組元素是指向函式入口地址的指標:函式返回值型別 (*陣列名[])().請注意,這裡為什麼要把“*陣列名[]”用括號擴起來呢?因為圓括號和陣列說明符的優先順序是等同的,如果不用圓括號把指標陣列說明表示式擴起來,根據圓括號和方括號的結合方向,那麼 *陣列名[]() 說明的是什麼呢?是元素返回值型別為指標的函式陣列。有這樣的函式陣列嗎?不知道。所以必須括起來,以保證陣列的每一個元素是指標。

}

第二種,矇騙法:

儘管函式不是變數,但它在記憶體中仍有其實體地址,該地址能夠賦給指標變數獲取函式地址的方法是:用不帶有括號和引數的函式名得到

函式名相當於一個指向其函式入口指標常量。 那麼既然函式名是一個指標常量,那麼就可以對其進行一些相應的處理,如強制型別轉換

那麼我們就可以把這個地址放在一個整形指標陣列中,然後作為函式指標呼叫即可。

完整例子:

#include<stdio.h>
intadd1(inta1,intb1);
intadd2(inta2,intb2);
intmain(void)
{
intnuma1=1,numb1=2;
intnuma2=2,numb2=3;
int(*op[2])(inta,intb);
op[0]=add1;
op[1]=add2;
printf("%d%d\n",op[0](numa1,numb1),op[1](numa2,numb2));
}
intadd1(inta1,intb1)
{
returna1+b1;
}
intadd2(inta2,intb2)
{
returna2+b2;
}

賦值

為函式指標陣列賦值有兩種方式:靜態定義和動態賦值

1. 靜態定義

在定義函式指標陣列的時候,已經確定了每個成員所對應的函式。例如:

void(*Array[])(void)={Stop,Run,Jump};

省略。這個函式指標陣列的成員有三個。從根本上講函式指標陣列依然是陣列,所以和陣列的定義類似,由於是靜態賦值,[ ]裡面的數字可以

Array[1]();//執行Run函式

也可以先定義一個函式指標陣列,在需要的時候為其賦值。為了還原其本來面目,我們先對這個執行特定型別的函式指標進行型別重定義,然後再用這個新資料型別來定義陣列。如下:2. 動態賦值

typedefvoid(*Funcint)(void);//此型別的函式指標指向的是無參、無返回值的函式。
FuncintArray[32];//定義一個函式指標陣列,其每個成員為Funcint型別的函式指標
Array[10]=INT_TIMER0;//為其賦值
Array[10]();//呼叫函式指標陣列的第11個成員指向的函式

You have an incredible number of choices to achieve delegates in C++. Here are the ones that came to my mind.

Option 1 : functors:

A function object may be created by implementingoperator()

struct Functor
{
     // Normal class/struct members

     int operator()(double d) // Arbitrary return types and parameter list
     {
          return (int) d + 1;
     }
};

// Use:
Functor f;
int i = f(3.14);

Option 2: lambda expressions (C++11only)

// Syntax is roughly: [capture](parameter list) -> return type {block}
// Some shortcuts exist
auto func = [](int i) -> double { return 2*i/1.15; };
double d = func(1);

Option 3: function pointers

int f(double d) { ... }
typedef int (*MyFuncT) (double d);
MyFuncT fp = &f;
int a = fp(3.14);

Option 4: pointer to member functions(fastest solution)

SeeFast C++ Delegate(onThe Code Project).

struct DelegateList
{
     int f1(double d) { }
     int f2(double d) { }
};

typedef int (DelegateList::* DelegateType)(double d);

DelegateType d = &DelegateList::f1;
DelegateList list;
int a = (list.*d)(3.14);

Option 5:std::function

(orboost::functionif your standard library doesn't support it). It is slower, but it is the most flexible.

#include <functional>
std::function<int(double)> f = [can be set to about anything in this answer]
// Usually more useful as a parameter to another functions

Option 6: binding (usingstd::bind)

Allows setting some parameters in advance, convenient to call a member function for instance.

struct MyClass
{
    int DoStuff(double d); // actually a DoStuff(MyClass* this, double d)
};

std::function<int(double d)> f = std::bind(&MyClass::DoStuff, this, std::placeholders::_1);
// auto f = std::bind(...); in C++11

Option 7: templates

Accept anything as long as it matches the argument list.

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}