天天看點

C++ 函數指針和指針函數總結

文章目錄

      • 函數指針
      • 指針函數
      • 傳回函數指針的函數
      • 函數指針實作函數重載

函數指針

函數指針是指向函數的指針變量,因而函數指針本身首先應是指針變量,正如用指針變量可指向整型變量、字元型、數組一樣,函數指針隻不過是指向函數的指針。
  • 函數指針的兩個用途

    調用函數和作函數的參數

  • 函數指針定義格式如下:

    函數類型 (* 指針變量名) (形參清單)

    "函數類型"為函數的傳回類型,由于()的優先級高于*,是以指針變量名外的括号必不可少,後面的"形參清單"表示指針變量指向的函數所帶的參數清單

例如:

int (*pf)(int x);
           

若寫成

int *pf(int x);
           

按照結合性和優先級來看就是pf先和()結合,它就變成了一個傳回整型指針的函數而不是函數指針了

  • 函數名和數組名一樣,實際上是一個位址,函數名代表了函數代碼的首位址,是以在指派時,直接将函數指針指向函數名就好了,

    pf=func

    pf=&func

    ,都是func的首位址
int (*pf)(int x);
pf=func;
pf=&func;
           
  • 用typedef方法可以有效減少括号的數量,以及理清層次。
typedef int (*PF)(int x);
PF pf;
pf=func;
//指派時函數func不帶括号,也不帶參數
pf=func();//error
pf=func(int x);//error
           
  • 函數指針絕對不能指向不同類型或者帶不同形參的函數
int main(){
    int func1(int x);
    double func2(double x);
    int func3(int x,int y);
    int (*pf)(int x);
    pf=func1;
    pf=func2;//錯誤
}
           
  • 函數指針作為變量,函數指針調用函數
void caller(void (*ptr)())//函數指針作為變量
{
    ptr();//調用ptr指向的函數
}
void func(){};
int main(){
    void (*p) ();
    p=func;
    caller(p);//傳遞函數位址到調用者
    return 0;
}
           

通過賦予不同的值給p,那麼調用者可以調用不同位址的函數,指派可以發生在運作時,這樣便能實作動态綁定,

虛函數的動态聯編是這樣實作的
  • 回調函數(Callback),實際上所謂回調函數,本質就是函數指針,使用回調函數實際上就是在調用某個函數(通常是API函數)時,将自己的一個函數(這個函數為回調函數)的位址作為參數傳遞給所調用的那個函數。

例如:C++标準模闆庫裡的sort排序函數:

template void sort{
    RandomAccessIterator _First,//需排序資料的第一個元素位置
    RandomAccessIterator _Last,//需排序資料的最後一個元素位置
    BinaryPredicate _Comp,//排序使用的比較算法
    
}
           

指針函數

指針函數是指傳回值是指針的函數,其本質上是一個函數。

函數都有傳回類型(如果不傳回值,則為無值型),隻不過指針函數傳回類型是某一類型的指針。

  • 定義格式

    傳回類型* 函數名稱(形式參數表);

    例如:
int *func(int x,int y);
           
  • 指針函數傳回的是一個位址值,經常用于傳回數組的某一進制素位址
  • 指針函數可以傳回堆位址,可以傳回全局或靜态變量的位址,但不要傳回局部變量的位址
int* func()//指針函數
{
    int value=1;
    return &value;//warning:傳回局部變量或臨時變量的位址
}
int main(){
    int *pret=func();//
    printf("%s",* pret);
    return 0;
}
           

程式能夠通過編譯,但會有運作時的錯誤。

傳回函數指針的函數

例如要聲明一個函數,它帶一個int參數,然後傳回一個函數指針,指針類型為int(*)(int int);

這個函數的名字叫func,如何寫呢?應寫成

int (* func(int))(int int);
           

用typedef定義傳回的函數類型,寫法如下

typedef int (* RetFunPtr) (int,int);//給函數指針取别名RetFunPtr
RetFunPtr func(int);//聲明函數func,函數func的參數為int,傳回值為函數指針
           

例如:

int add(int x,int y){
    int i=x+y;
    return i;
}
int (* FuncPtr()) (int,int)//定義傳回函數指針的函數
{
    return add;
}
int main(){
    int (* fptr) (int,int)=FuncPtr();
    printf("%d",fptr(10,10);
    return 0;
}
           

技巧:

了解複雜聲明時的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括号就跳轉閱讀的方向;括号内分析完就跳出括号,還是按先右後左的順序,如此循環,直到整個聲明分析完。

在上面代碼中,了解注釋部分,可以按右左法則進行:FuncPtr是它的名稱,先往右,碰到一個括号,說明FuncPtr為函數,且無函數參數,再往左,碰到*,說明該函數傳回為指針,

(* FuncPtr())

中的内容分析完了,跳出括号,繼續向右,再次碰到括号,說明該傳回的是一個函數指針,該括号中有兩個int參數,說明函數指針所指向函數帶兩個int型參數,再往左,碰到int,說明該函數指針指向的函數的傳回值為int類型,到此分析完畢。

總結起來,這串代碼的意思是,FuncPtr是一個無參函數且傳回值為函數指針,該函數指針指向函數帶兩個int型參數,且所指向函數傳回值為int

函數指針實作函數重載

C語言中無重載特性,隻能通過函數指針的方式實作類似重載的功能。在此不做展開,僅作了解

繼續閱讀