c++:STL函數對象、謂詞、內建函數對象、函數適配器

目錄

 一、函數對象

二、謂詞

三、內建函數對象

四、函數適配器

4.1 函數對象適配器

4.2 取反適配器

4.3 函數指針適配器

4.4 成員函數適配器


 

 

 一、函數對象

重載函數調用操作符的類,其對象常稱爲函數對象(function object),即它們是行爲類似函數的對象,也叫仿函數(functor),其實就是重載“()”操作符,使得類對象可以像函數那樣調用。

注意:

1.函數對象(仿函數)是一個類,不是一個函數。

2.函數對象(仿函數)重載了”() ”操作符使得它可以像函數一樣調用。

分類:假定某個類有一個重載的operator(),而且重載的operator()要求獲取一個參數,我們就將這個類稱爲一元仿函數”(unary functor);相反,如果重載的operator()要求獲取兩個參數,就將這個類稱爲二元仿函數”(binary functor)

函數對象的作用主要是什麼?STL提供的算法往往都有兩個版本,其中一個版本表現出最常用的某種運算,另一版本則允許用戶通過template參數的形式來指定所要採取的策略。

 

//函數對象是重載了函數調用符號的類
class MyPrint
{
public:
	MyPrint()
	{
		m_Num = 0;
	}
	int m_Num;

public:
	void operator() (int num)
	{
		cout << num << endl;
		m_Num++;
	}
};

//函數對象
//重載了()操作符的類實例化的對象,可以像普通函數那樣調用,可以有參數 ,可以有返回值
void test01()
{
	MyPrint myPrint;
	myPrint(20);

}
// 函數對象超出了普通函數的概念,可以保存函數的調用狀態
void test02()
{
	MyPrint myPrint;
	myPrint(20);
	myPrint(20);
	myPrint(20);
	cout << myPrint.m_Num << endl;
}

void doBusiness(MyPrint print,int num)
{
	print(num);
}

//函數對象作爲參數
void test03()
{
	//參數1:匿名函數對象
	doBusiness(MyPrint(),30);
}

總結:

1、函數對象通常不定義構造函數和析構函數,所以在構造和析構時不會發生任何問題,避免了函數調用的運行時問題。

2、函數對象超出普通函數的概念,函數對象可以有自己的狀態

3、函數對象可內聯編譯,性能好。用函數指針幾乎不可能

4、模版函數對象使函數對象具有通用性,這也是它的優勢之一 

 

二、謂詞

謂詞是指普通函數重載的operator()返回值是bool類型的函數對象(仿函數)。如果operator接受一個參數,那麼叫做一元謂詞,如果接受兩個參數,那麼叫做二元謂詞,謂詞可作爲一個判斷式。

class Greater20
{
public:
	bool operator()(int val)
	{
		return val > 20;
	}
};

class myCompare
{
public:
	bool operator()(int v1 , int v2)
	{
		return v1 > v2;
	}
};

//一元謂詞
void test01()
{
	vector<int>v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//找到第一個大於20的元素
	vector<int>::iterator ret = find_if(v.begin(), v.end(), Greater20());
	if (ret != v.end())
	{
		cout << "找到了元素大於20的值爲: " << *ret << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}

	//二元謂詞
	sort(v.begin(), v.end(), myCompare());
}

 

三、內建函數對象

STL內建了一些函數對象。

分爲:  算數類函數對象,  關係運算類函數對象,邏輯運算類仿函數。

這些仿函數所產生的對象,用法和一般函數完全相同,當然我們還可以產生無名的臨時對象來履行函數功能。使用內建函數對象,需要引入頭文件 #include<functional>

 

  • 6個算數類函數對象,除了negate是一元運算,其他都是二元運算。

template<class T> T plus<T>//加法仿函數

template<class T> T minus<T>//減法仿函數

template<class T> T multiplies<T>//乘法仿函數

template<class T> T divides<T>//除法仿函數

template<class T> T modulus<T>//取模仿函數

template<class T> T negate<T>//取反仿函數

  • 6個關係運算類函數對象,每一種都是二元運算。

template<class T> bool equal_to<T>//等於

template<class T> bool not_equal_to<T>//不等於

template<class T> bool greater<T>//大於

template<class T> bool greater_equal<T>//大於等於

template<class T> bool less<T>//小於

template<class T> bool less_equal<T>//小於等於

 

  • 邏輯運算類運算函數,not爲一元運算,其餘爲二元運算。

template<class T> bool logical_and<T>//邏輯與

template<class T> bool logical_or<T>//邏輯或

template<class T> bool logical_not<T>//邏輯非

 

四、函數適配器

都要包含頭文件:

#include <functional>

 

4.1 函數對象適配器

步驟:

  • 1 綁定  bind2nd
  • 2 繼承 public binary_function<參數類型,參數類型 ,返回值類型>
  • 3 加const
class MyPrint : public binary_function<int,int ,void>
{
public:
	void operator()(int num , int start) const 
	{
		cout << "num = " <<  num << " start = " << start << " sum = " << num  + start  << endl;
	}
};

void test01()
{
	vector<int>v;
	for (int i = 0; i < 10;i++)
	{
		v.push_back(i);
	}
	cout << "請輸入起始累加值:" << endl;
	int start;
	cin >> start;

	for_each(v.begin(), v.end(), bind2nd( MyPrint(), start)  ); //推薦
	//for_each(v.begin(), v.end(), bind1st(MyPrint(), start));
}

 

4.2 取反適配器

步驟:

  • 1 取反適配器 not1
  • 2 繼承 public unary_function<參數類型,返回值類型>
  • 3 加const
void test02()
{
	//一元取反適配器
	vector<int>v;
	for (int i = 0; i < 10;i++)
	{
		v.push_back(i);
	}

	//vector<int>::iterator ret = find_if(v.begin(), v.end(), not1( GreaterFive()));
	vector<int>::iterator ret = find_if(v.begin(), v.end(), not1(  bind2nd( greater<int>(), 5 )));
	if (ret != v.end())
	{
		cout << "找到小於5的數據爲" << *ret << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}

	//二元取反適配器
	sort(v.begin(), v.end(),  not2( less<int>()));
	for (vector<int>::iterator it = v.begin(); it != v.end();it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

 

4.3 函數指針適配器

將myPrint函數指針 適配成函數對象即可。利用 ptr_fun

void myPrint(int val , int start)
{
	cout << val + start << endl;
}

void test03()
{

	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	cout << "請輸入起始累加值:" << endl;
	int start;
	cin >> start;

	for_each(v.begin(), v.end(), bind2nd( ptr_fun(myPrint), start));
}

 

4.4 成員函數適配器

利用mem_fun_ref 將成員函數進行適配

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	void showPerson()
	{
		cout << "姓名: " << this->m_Name << " 年齡: " << this->m_Age << endl;
	}

	void addAge()
	{
		this->m_Age++;
	}

	string m_Name;
	int m_Age;
};

void test04()
{
	vector<Person>v;

	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);

	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);

	for_each(v.begin(), v.end(), mem_fun_ref( &Person::showPerson));
	for_each(v.begin(), v.end(), mem_fun_ref(&Person::addAge));
	cout << "-------------------------" << endl;
	for_each(v.begin(), v.end(), mem_fun_ref(&Person::showPerson));
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章