首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 那些細節:函數指針、成員函數指針、回調機制完整詳解

     編輯:關於C++

一、普通函數指針

定義與 typedef

格式:返回類型 (*指針名)(參數列表)。用 typedef 簡化:


typedef void (*pFunc)(int); // 定義類型別名 pFunc

void PrintInt(int i) { cout << i << endl; }

int main() {
    pFunc func = PrintInt; // 或 &PrintInt
    func(1); // 調用
    return 0;
}

二、成員函數指針

靜態成員函數指針

與普通函數指針相同,無 this 指針:


class Base {
public:
    static void Print(int num) { cout << num << endl; }
};
typedef void (*pFunc)(int);
pFunc func = &Base::Print; // 直接賦值
func(1);

非靜態成員函數指針

語法:返回類型 (類名::*指針名)(參數列表)。調用需對象實例:


class Base {
public:
    void Print(int num) { cout << num << endl; }
};
typedef void (Base::*pFunc)(int); // 類作用域

int main() {
    Base base;
    pFunc func = &Base::Print; // 必須用 &Base::Print
    (base.*func)(1); // 對象.指針 調用
    // 或指針對象
    Base* ptr = &base;
    (ptr->*func)(1);
    return 0;
}

關鍵規則:

  • 賦值必須用 &Class::func,不可省略 &
  • 不可用對象賦值(&base.Print 錯誤)
  • 調用語法:(obj.*func)(args) 或 (ptr->*func)(args)

多態性與虛函數

基類虛函數指針可指向派生類覆寫函數:


class Base { public: virtual void Print(int n) { cout << "Base: " << n << endl; } };
class Child : public Base { public: void Print(int n) override { cout << "Child: " << n << endl; } };

int main() {
    typedef void (Base::*pFunc)(int);
    pFunc func = &Base::Print;
    Base base; Child child;
    (base.*func)(1);  // Base: 1
    (child.*func)(1); // Child: 1(多態生效)
    cout << sizeof(pFunc) << endl; // 通常 4/8 字節(單繼承)
    return 0;
}

原理:成員函數指針隱含 this 參數,實際簽名等價於 void (*)(Base*, int)。派生類對象可隱式轉換為基類指針,虛函數表機制保證多態。

三、函數指針作用:參數傳遞與回調

作為函數參數


typedef int (*pcall)(int, int);
int Add(int a, int b) { return a + b; }
int Sub(int a, int b) { return a - b; }

void Func(pcall p, int x, int y) {
    cout << "result: " << p(x, y) << endl;
}
int main() {
    Func(Add, 1, 2); // 3
    Func(Sub, 3, 2); // 1
}

回調機制詳解

比喻: 普通調用 = 親自去買東西;回調 = 預定蛋糕留電話,做好通知取貨。

流程: 1) 註冊回調函數 2) 條件滿足時調用 3) 回調執行

無回調:輪詢等待(阻塞/忙等)


class Baker {
    int time = 0; const int MAX = 10;
    bool MakeCake() { return ++time == MAX; }
};
int main() {
    Baker b;
    while (!b.MakeCake()) { cout << "not ready\n"; Sleep(1000); }
    cout << "ready! get it!\n";
}

缺點:調用線程被佔用,無法做其他事。

有回調:異步通知


typedef void (*CallbackFunc)();
class Baker {
    int time = 0; const int MAX = 10;
    CallbackFunc cb;
public:
    void Register(CallbackFunc f) { cb = f; cout << "registered\n"; }
    void MakeCake() {
        while (time < MAX) { time++; Sleep(1000); }
        cout << "cake ready!\n";
        if (cb) cb(); // 通知
    }
};
void OnReady() { cout << "I'll get it!\n"; }
int main() {
    Baker b;
    b.Register(OnReady);
    b.MakeCake(); // 同步演示,實際可放入線程
    return 0;
}

優點:註冊後主線程自由,完成時自動通知。C# 用委托簡化此模式,C++ 需手動實現。

四、函數指針 vs 指針函數

  • 函數指針:指向函數的指針,本質是指針。int (*pFunc)();
  • 指針函數:返回指針的函數,本質是函數。int* PointerFunc();
  • 區別:* 與名字在一起 = 函數指針;* 與返回類型在一起 = 指針函數
  • 可組合:int* (*pFUN)(); 指針函數的函數指針
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved