習慣 qsort 函數指標的開發者,初次使用 std::sort 時常直接傳遞函數指標。雖然語法可行,但錯失了仿函數(Function Object / Functor)的核心優勢——攜帶狀態。
需對表格排序,每欄位可能升序/降序、類型不同,比較邏輯需依據執行期資訊(如欄位型別、排序方向)決定。若用普通函數或靜態函數,無法存取物件成員變數;若用類別成員函數,又不符合 std::sort 的呼叫慣例。
class MyClass {
// ... 類別成員資料 ...
struct DoCompare {
// 建構子接收外部狀態(如 this 指標)
DoCompare(const MyClass& info) : m_info(info) {}
const MyClass& m_info; // 保存狀態參考
// 重載 operator() 使物件可像函數一樣呼叫
bool operator()(const int& i1, const int& i2) {
// 使用 m_info 進行比較邏輯判斷
// return 比較結果;
}
};
void doSort() {
// 建立仿函數物件,傳入 *this 作為狀態
std::sort(arr, arr + someSize, DoCompare(*this));
}
};
| 特性 | 函數指標 | 仿函數 |
|---|---|---|
| 攜帶狀態 | ❌ 無法 | ✅ 透過成員變數 |
| 內聯優化 | ❌ 難以內聯 | ✅ 編譯器易內聯 |
| 類型安全 | ⚠️ 需強制轉型 | ✅ 模板推導類型 |
| 效能 | 較低 | 通常更高 |
std::sort 要求比較函數滿足 Strict Weak Ordering:
comp(x, x) == falsecomp(a, b) && comp(b, c) → comp(a, c)!comp(a,b) && !comp(b,a) 視為等價,等價關係具傳遞性// ❌ 錯誤:違反嚴格弱序
bool descBad(int a, int b) { return a >= b; }
// ✅ 正確:嚴格小於
bool descGood(int a, int b) { return a > b; }
原因: >= 的反面不是 <,而是 <=。若 a == b,descBad 回傳 true,導致 comp(a,b) && comp(b,a) 同時為真,違反不可自反性,可能造成標準庫實作存取越界(如無限遞迴或記憶體錯誤)。
std::sort(v.begin(), v.end(), [&](auto a, auto b){ return a > b; });std::binary_function:C++11 已棄用,C++17 移除。仿函數是 C++ 泛型演算法的靈魂,理解其「可呼叫物件」本質與狀態封裝能力,能解決函數指標無法處理的動態比較需求。記住:比較函數必須實作嚴格弱序,否則行為未定義。