C++學習筆記(六)函數對象

函數對象基本介紹

函數對象是一個普通的類對象,它的不普通之處在於它表現出一個函數的特徵,即可以像普通函數那樣進行函數調用操作。它的實現方式是對call操作符進行重載。

函數對象通常具有比普通函數更大的靈活性,例如,我們看下面這個例子。

bool GT6(int data) {
	return data > 6;
}

這個函數的實現目的是比較一個數是否大於6,加如我們現在需要這樣的用戶需求,就是測試一組10個用戶輸入的數字是否分別大於1~10,如果使用普通的函數,我們就不得不實現10個這樣的函數版本(暫時不考率函數模板)。換個思路,如果我們使用函數對象,結果就大不一樣了:
class GT_int {
	public:
		GT_int(int pn):n(pn) {
		}

		bool operator()(int data) {
			return data > n;
		}
	private:
		int n;
}

以上是一個函數對象的實現方式,它重載了call運算符,使它可以實現和函數同樣的操作,使用構造函數來確定所比較的值。以下是它的使用方式:
int data
for (int i = 1; cin >> data && i <= 10; ++i) {
	GT_int gt(i);
	cout<< gt(data)<< endl;
}

STL中的函數對象

函數對象在許多情況下非常有用,例如,它可以顯示的指定STL算法庫中的算法應該使用什麼樣的基本邏輯,例如,看下面的排序例子:

sort(svec.begin(), svec.end(), greater<string>());

一般說來,默認的sort函數使用’<’操作符對容器元素進行排序,而上面這個重載版本則使用了第三個參數greater<string>(),它是function頭文件中定義的函數對象,可以比較第一個操作數是否大於第二個操作數,也就是說傳遞這個函數對象將使sort函數按降序方式進行排序。

在STL中,函數對象按照參數以及返回值的不同基本可以按照如下分類:
1. 產生器 沒有參數
2. 一元函數 一個參數
3. 二元函數 兩個參數
4. 一元謂詞 一個參數,返回類型爲bool型
5. 二元謂詞 兩個參數,返回類型爲bool型

我們可以看一下函數accumulate的聲明:
template <class InputIterator, class T, class BinaryOperation>
          T accumulate ( InputIterator first, InputIterator last, T init,
                         BinaryOperation binary_op );
最後一個參數就要求是必須是一個二元函數。

函數適配器

前面已經介紹過容器適配器,迭代器適配器,今天我們來看一下函數適配器。和所有的適配器類似,函數適配器是用來讓一個函數對象表現出另外一種類型的函數對象的特徵。因爲,許多情況下,我們所持有的函數對象或普通函數的參數個數或是返回值類型並不是我們想要的,這時候就需要函數適配器來爲我們的函數進行適配。函數適配器最主要的可以分爲兩類:

1. 綁定適配器

該類適配器用於將二元函數適配成一元函數。

上圖描述了綁定適配器的兩種形式,binder1st將適配參數綁定到第一個參數上,binder2nd將適配參數綁定到第二個參數上。至於bind1st和bind2nd則實際上是爲了避免冗長的聲明而方便使用的適配模板函數而已。
我們還是先看一個例子:
count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));

less_equal是STL爲我們提供的一個函數對象,它有兩個參數,器作用是比較第一個參數值是否<=第二個參數值。但是count_if要求我們第三個參數必須是一個一元謂詞,所以我們用bind2nd對該函數對象進行適配,將10綁定到該函數對象的第二個參數上。現在cont_if執行的功能實際上就變成了查找給定序列中值<=10的元素的個數。

2. 反相器適配器

這一類適配器主要實現的功能是對函數的返回值進行適配,它對bool值進行取反,將true適配成false,false適配成ture。
例如我們如果想計算給定序列中元素值大於10的元素的個數,可以這樣寫:
count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)));

STL爲我們提供了兩種反相器適配器,not1和not2,可進行適配的函數的參數分別是1個和兩個。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章