系列: C++
cpp
291 行
· 更新於 2026-04-03
function_objects.cpp
C++/Part3_泛型與STL/Ch15_Lambda與函式物件/function_objects.cpp
// Ch15 — 函式物件(Functors)示範
// 編譯:g++ -std=c++17 -Wall -o function_objects function_objects.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional> // std::plus, std::greater, std::multiplies, etc.
#include <string>
#include <iomanip>
// 輔助函式:印出分隔線
void section(const std::string& title) {
std::cout << "\n===== " << title << " =====\n";
}
template<typename T>
void printVec(const std::string& label, const std::vector<T>& v) {
std::cout << label;
for (const auto& x : v) std::cout << x << " ";
std::cout << "\n";
}
// ============================================================
// 1. 基本函式物件:重載 operator()
// ============================================================
class Adder {
int offset_;
public:
explicit Adder(int offset) : offset_(offset) {}
int operator()(int x) const {
return x + offset_;
}
};
// ============================================================
// 2. 有狀態的函式物件:計數器
// ============================================================
class Counter {
int count_ = 0;
public:
void operator()() {
++count_;
}
// 用於 for_each 時接受元素參數
void operator()(int) {
++count_;
}
int getCount() const { return count_; }
};
// ============================================================
// 3. 有狀態的函式物件:累加器
// ============================================================
class Accumulator {
double total_ = 0.0;
public:
void operator()(double value) {
total_ += value;
}
double getTotal() const { return total_; }
};
// ============================================================
// 4. 謂詞函式物件(用於條件判斷)
// ============================================================
class InRange {
int low_, high_;
public:
InRange(int low, int high) : low_(low), high_(high) {}
bool operator()(int x) const {
return x >= low_ && x <= high_;
}
};
// ============================================================
// 5. 比較函式物件(用於排序)
// ============================================================
struct Student {
std::string name;
int score;
};
class CompareByScore {
bool descending_;
public:
explicit CompareByScore(bool desc = true) : descending_(desc) {}
bool operator()(const Student& a, const Student& b) const {
return descending_ ? a.score > b.score : a.score < b.score;
}
};
// ============================================================
// 6. 普通函式(用於比較)
// ============================================================
int doubleValue(int x) {
return x * 2;
}
bool isPositive(int x) {
return x > 0;
}
int main() {
// ========================================================
// 1. 基本函式物件
// ========================================================
section("1. 基本函式物件");
Adder add5(5);
Adder add10(10);
std::cout << "add5(3) = " << add5(3) << "\n";
std::cout << "add5(7) = " << add5(7) << "\n";
std::cout << "add10(3) = " << add10(3) << "\n";
// 搭配 transform 使用
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> result(nums.size());
std::transform(nums.begin(), nums.end(), result.begin(), Adder(100));
printVec("原始:", nums);
printVec("加 100:", result);
// ========================================================
// 2. 有狀態的函式物件
// ========================================================
section("2. 有狀態的函式物件(Counter)");
// for_each 回傳函式物件的副本,可用來取得最終狀態
std::vector<int> data = {10, 20, 30, 40, 50};
Counter c = std::for_each(data.begin(), data.end(), Counter());
std::cout << "for_each 遍歷了 " << c.getCount() << " 個元素\n";
section("有狀態的函式物件(Accumulator)");
std::vector<double> prices = {29.99, 15.50, 42.00, 8.75, 33.25};
Accumulator acc = std::for_each(prices.begin(), prices.end(), Accumulator());
std::cout << "商品價格:";
for (double p : prices) std::cout << "$" << p << " ";
std::cout << "\n";
std::cout << "總價:$" << std::fixed << std::setprecision(2)
<< acc.getTotal() << "\n";
// ========================================================
// 3. 謂詞函式物件
// ========================================================
section("3. 謂詞函式物件(InRange)");
std::vector<int> scores = {45, 72, 88, 55, 91, 63, 78, 50, 95, 82};
printVec("全部分數:", scores);
// 計算 70-89 分的人數
InRange bRange(70, 89);
int bCount = std::count_if(scores.begin(), scores.end(), bRange);
std::cout << "70-89 分(B 等)有 " << bCount << " 人\n";
// 篩選 60-100 分(及格)的分數
InRange passRange(60, 100);
std::vector<int> passed;
std::copy_if(scores.begin(), scores.end(),
std::back_inserter(passed), passRange);
printVec("及格分數:", passed);
// 可以用不同參數建立不同範圍的謂詞
InRange excellent(90, 100);
int excellentCount = std::count_if(scores.begin(), scores.end(), excellent);
std::cout << "90-100 分(優秀)有 " << excellentCount << " 人\n";
// ========================================================
// 4. 比較函式物件用於排序
// ========================================================
section("4. 比較函式物件用於排序");
std::vector<Student> students = {
{"Alice", 88}, {"Bob", 95}, {"Charlie", 72},
{"Diana", 88}, {"Eve", 91}
};
// 分數降序
std::sort(students.begin(), students.end(), CompareByScore(true));
std::cout << "降序排列:\n";
for (const auto& s : students) {
std::cout << " " << std::setw(8) << s.name << ":" << s.score << "\n";
}
// 分數升序
std::sort(students.begin(), students.end(), CompareByScore(false));
std::cout << "升序排列:\n";
for (const auto& s : students) {
std::cout << " " << std::setw(8) << s.name << ":" << s.score << "\n";
}
// ========================================================
// 5. 預定義函式物件
// ========================================================
section("5. 預定義函式物件(<functional>)");
std::vector<int> v = {5, 2, 8, 1, 9, 3, 7};
printVec("原始:", v);
// std::greater — 降序排列
std::sort(v.begin(), v.end(), std::greater<int>());
printVec("greater 降序:", v);
// std::less — 升序排列(預設行為)
std::sort(v.begin(), v.end(), std::less<int>());
printVec("less 升序:", v);
// std::plus — 累加
int sum = std::accumulate(v.begin(), v.end(), 0, std::plus<int>());
std::cout << "plus 累加:" << sum << "\n";
// std::multiplies — 累乘
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
std::cout << "multiplies 累乘:" << product << "\n";
// std::negate — 取負
std::vector<int> negated(v.size());
std::transform(v.begin(), v.end(), negated.begin(), std::negate<int>());
printVec("negate 取負:", negated);
// C++14 透明版本(不需指定型別)
std::sort(v.begin(), v.end(), std::greater<>());
printVec("greater<>() 降序:", v);
// ========================================================
// 6. 普通函式 vs 函式物件 vs Lambda 比較
// ========================================================
section("6. 三種方式比較");
std::vector<int> values = {1, 2, 3, 4, 5};
std::vector<int> out1(5), out2(5), out3(5);
// 方式 1:普通函式
std::transform(values.begin(), values.end(), out1.begin(), doubleValue);
printVec("普通函式 doubleValue:", out1);
// 方式 2:函式物件
std::transform(values.begin(), values.end(), out2.begin(), Adder(0));
// Adder(0) 加 0 等於複製,這裡用 multiplies 示範
std::transform(values.begin(), values.end(), out2.begin(),
[](int x) { return x * 2; });
printVec("函式物件(lambda):", out2);
// 方式 3:Lambda
std::transform(values.begin(), values.end(), out3.begin(),
[](int x) { return x * 2; });
printVec("Lambda:", out3);
std::cout << "\n比較摘要:\n";
std::cout << " 普通函式:簡單但無法攜帶狀態\n";
std::cout << " 函式物件:可攜帶狀態,可複用,編譯器容易內聯\n";
std::cout << " Lambda: 語法簡潔,適合一次性使用,C++14 起支援泛型\n";
// ========================================================
// 7. 綜合範例:多層篩選與轉換
// ========================================================
section("7. 綜合範例");
std::vector<int> rawData = {-5, 12, -3, 8, 0, -1, 15, 7, -9, 20, 3};
printVec("原始資料:", rawData);
// 使用普通函式篩選正數
std::vector<int> positives;
std::copy_if(rawData.begin(), rawData.end(),
std::back_inserter(positives), isPositive);
printVec("正數:", positives);
// 使用函式物件篩選特定範圍
std::vector<int> inRange;
std::copy_if(rawData.begin(), rawData.end(),
std::back_inserter(inRange), InRange(0, 10));
printVec("0-10 範圍:", inRange);
// 使用預定義函式物件排序
std::sort(positives.begin(), positives.end(), std::greater<int>());
printVec("正數降序:", positives);
// 使用預定義函式物件累加
int positiveSum = std::accumulate(positives.begin(), positives.end(),
0, std::plus<int>());
std::cout << "正數總和:" << positiveSum << "\n";
return 0;
}
相關文章
C++
c
更新於 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
閱讀文章 →
C++
c
更新於 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
閱讀文章 →
C++
cpp
更新於 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
閱讀文章 →
C++
c
更新於 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
閱讀文章 →
C++
c
更新於 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
閱讀文章 →
C++
cpp
更新於 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
閱讀文章 →