首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C++ 函式指標與函式物件完整指南:從 C 風格回調到 STL 仿函數

     編輯:更多程式設計知識

前言

函式指標是 C 語言回調基石;函式物件 (Functor) 是 C++ 泛型程式設計核心。本文系統對比兩者語法、效能、表達力,並展示 STL 如何以函式物件實現高效演算法。

第一篇:函式指標

宣告語法


// 普通函式宣告
int func(int x);

// 函式指標宣告:括號關鍵
int (*pf)(int x);

// typedef 簡化
typedef int (*PF)(int x);
PF pf;

基本用法:指向函式、透過指標呼叫


void bar(char ch, int i) { std::cout << "bar " << ch << ' ' << i << "\n"; }

typedef void (*PFT)(char, int);
PFT pft = bar;      // 指向 bar
pft('e', 91);       // 呼叫:bar e 91
(*pft)('e', 91);    // 等價寫法

進階用法:作為函式參數 (回調)


void foo(char ch, int i, PFT pf) {
    pf(ch, i);  // 呼叫傳入的函式
}

foo('e', 12, pft);  // 靈活切換行為

優缺點

  • ✅ C 相容、零開銷、支援函式指標陣列/表驅動
  • ❌ 無狀態捕獲、無法內聯 (間接呼叫阻礙最佳化)、型別安全弱
  • ❌ 無法直接綁定成員函式 (需 std::mem_fn 或 Lambda)

第二篇:函式物件 (Functor)

定義:重載 operator() 的類別


struct Adder {
    int operator()(int a, int b) const {
        std::cout << a << '+' << b << '=' << a+b << "\n";
        return a;
    }
};

Adder add;
add(1, 3);  // 像函式呼叫:1+3=4

作為函式參數:以引用傳遞避免切割


int addFunc(int a, int b, Adder& func) {
    return func(a, b);
}

泛型化:模板仿函數


struct GenericAdder {
    template
    T operator()(T a, T b) const {
        std::cout << a << '+' << b << '=' << a+b << "\n";
        return a;
    }
};

template
T addFuncT(T a, T b, Func& f) { return f(a, b); }

GenericAdder gadd;
addFuncT(2, 4, gadd);      // int
addFuncT(1.4, 2.3, gadd);  // double

三、 核心差異對比

維度函式指標函式物件
狀態無狀態可攜帶狀態 (成員變數)
內聯最佳化困難 (間接呼叫)容易 (編譯器可內聯 operator())
型別安全簽名匹配即可模板參數推導強型別
成員函式綁定需 std::mem_fnLambda 捕獲 this 即可
STL 相容性可用但受限標準要求 (仿函數概念)

四、 STL 中的仿函數應用


#include 
#include 
#include 

std::vector v = {5, 2, 8, 1, 9};

// 1. 標準仿函數
std::sort(v.begin(), v.end(), std::greater());  // 降序

// 2. Lambda (C++11) - 最現代寫法
std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; });

// 3. 狀態仿函數:計算大於閾值的個數
struct GreaterThan {
    int threshold;
    GreaterThan(int t) : threshold(t) {}
    bool operator()(int x) const { return x > threshold; }
};
int count = std::count_if(v.begin(), v.end(), GreaterThan(5));  // 攜帶狀態

五、 現代 C++ 最佳實踐

  1. 優先 Lambda:就地定義、捕獲上下文、型別推導、可轉 std::function。
  2. 需跨編譯單元/儲存:用 std::function<Sig> (型別擦除,略有開銷)。
  3. 效能關鍵路徑:模板參數化仿函數 (如 STL 演算法),避免 std::function 型別擦除成本。
  4. C API 互操作:僅能用函式指標,Lambda 無捕獲可隱式轉換:(+[](int x){return x;})。

六、 進階:仿函數分類與型別特徵


#include 

// 判斷是否為可呼叫物件
template
using is_callable = std::is_invocable;

// C++20 concepts
template F>
void call_with_int(F f) { f(42); }

結語

函式指標是「指向程式碼的指標」;函式物件是「可呼叫的物件」。後者以狀態封裝、內聯最佳化、型別豐富三大優勢,成為 C++ 泛型程式設計 (STL、Boost、現代標準庫) 的基石。掌握從函式指標 → 仿函數 → Lambda → Concepts 的演進脈絡,是精通現代 C++ 的關鍵里程碑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved