仿函數(functor)是一種封裝函數的類別,其中封裝的函數可以像一般函數一樣呼叫,但是因為他是封裝在類別中的,所以可以使用類別的封裝和繼承特性。
在 C++ 中,仿函數是通過將函數的原型封裝在類別中,並實現一個重載了括號運算子的成員函數,來實現的。這樣就可以將仿函数當作一般函數一樣使用。
例如,我們可以定義一個仿函數類別 Plus,封裝了一個加法函數:
class Plus
{
public:
int operator()(int a, int b) const
{
return a + b;
}
};
然後我們就可以像呼叫函數一樣使用這個仿函數:
Plus plus;
int result = plus(1, 2); // result 的值是 3
在 C++ 中,仿函數常用於將函數作為參數傳遞給其他函數。例如,我們可以寫一個函數 apply,它接受一個仿函數和一個整數陣列,並對整數陣列中的每個元素使用仿函数進行計算:
template
void apply(Func f, int* array, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
array[i] = f(array[i]);
}
}
然後我們可以使用任意的仿函數呼叫 apply 函數:
int array[5] = { 1, 2, 3, 4, 5 };
apply(Plus(), array, 5); // array 現在是 { 2, 4, 6, 8, 10 }
仿函數也可以用於 STL 算法中,例如 std::sort 函數。我們可以傳遞一個仿函數來定義排序的順序:
#include
#include
std::sort(array, array + 5, std::greater()); // array 現在是 { 5, 4, 3, 2, 1 }
此外,仿函數還可以用於封裝非函數的操作,例如成員函數或操作符運算。
例如,我們可以寫一個仿函數類別封裝 std::vector 的 push_back 操作:
#include
class VectorPusher
{
public:
VectorPusher(std::vector& v) : v_(v) {}
void operator()(int x) const
{
v_.push_back(x);
}
private:
std::vector& v_;
};
std::vector v;
VectorPusher pusher(v);
pusher(1);
pusher(2);
pusher(3);
它可以讓我們將函數或其他操作封裝在類別中,並像呼叫函數一樣使用。仿函數的一個主要優點是它可以接受參數和返回結果,並且可以使用類別的封裝和繼承特性。
在 C++ 中,仿函數的用途非常廣泛,例如:
将函数作为参数传递给其他函数,例如 std::sort 函数。
封装非函数的操作,例如成员函数或运算符运算。
使用類別的封裝和繼承特性,實現函數指针的功能。
此外,仿函数也有一些缺點,例如:
代码可能會變得較為複雜。
仿函數的性能通常不如直接使用函數。
仿函數不能直接使用函數指针,必须使用 std::function 或其他方法。
在 C++ 中,仿函数可以使用 std::function 模板類型來實現。std::function 是一個泛型類型,可以封裝任意可被呼叫的對象,例如函數、仿函數、Lambda 表達式等。
例如,我們可以使用 std::function 封裝一個仿函數:
#include
std::function plus = Plus();
int result = plus(1, 2); // result 的值是 3
//也可以使用 std::function 封裝一個 Lambda 表達式:
std::function plus = [](int a, int b) { return a + b; };
int result = plus(1, 2); // result 的值是 3
使用 std::function 可以讓我們更方便地使用仿函數和其他可被呼叫的對象,而不用擔心底層實現的細節。
此外,C++11 標準引入了 Lambda 表達式,這是一種匿名函數的寫法。Lambda 表達式可以方便地寫出簡單的仿函數,例如:
auto plus = [](int a, int b) { return a + b; };
int result = plus(1, 2); // result 的值是 3
Lambda 表達式可以像一般函數一樣使用,但是因為它是匿名的,所以不能再其他地方引用。
仿函數和 Lambda 表達式是 C++ 中常用的函數式编程技术,它們可以讓我們更方便地使用函数作為参数或返回值。