C++可調用對象學習筆記

可調用對象定義:

具有函數行爲或功能的一組語句視爲可調用對象;一組執行任務的語句都可以視爲一個函數,一個可調用對象。在程序設計的過程中,我們習慣於把那些具有複用性的一組語句抽象爲函數,把變化的部分抽象爲函數的參數。C++中具有函數這種行爲的方式有很多。

1.普通函數 
2.類成員函數
3.類靜態函數
4.函數指針
5.重載了函數調用運算符的類(該類的對象又稱爲:函數對象或仿函數)
6.Lamada表達式
7.標準庫function類型
8.標準庫bind函數

1、    普通函數定義與調用很簡單,不再贅述。
2、    3、類成員函數與類靜態成員函數的區別
(1)類靜態成員函數被類的所有的對象共有,不屬於某一個對象。通過類名::就可以直接調用。
(2)類成員函數的參數列表中隱含着類this指針,類靜態成員函數跟普通的成員函數比,沒有隱藏的this指針作爲參數。這一點可用於封裝線程類。
(3)靜態成員函數只可以訪問靜態成員變量。

4、    函數指針
(1)函數指針:指向函數的指針變量。 因此“函數指針”本身首先應是指針變量,只不過該指針變量指向了函數。
(2)函數指針有兩個用途:調用函數和做函數的參數。
(3)函數指針的聲明方法爲:
返回值類型 ( * 指針變量名) ([形參列表]);

 demo:

#include <iostream>

using namespace std;
// 聲明一個compute函數指針;該函數指針指向:有兩個int型參數並且返回值爲int型的函數,這也是該指針的類型
typedef int(*compute)(int, int);

int max(int x, int y) { return x >= y ? x : y; }
int min(int x, int y) { return x <= y ? x : y; }
int add(int x, int y) { return x + y; }
int multiply(int x, int y) { return x * y; }

// 一個包含函數指針作爲回調的函數
int compute_x_y(int x, int y, int(*compute)(int, int))
{
	//調用回調函數
	return compute(x, y);
}

int main(void)
{
	int x = 2;
	int y = 5;
	std::cout << "max: " << compute_x_y(x, y, max) << std::endl; // max: 5
	std::cout << "min: " << compute_x_y(x, y, min) << std::endl; // min: 2
	std::cout << "add: " << compute_x_y(x, y, add) << std::endl; // add: 7
	std::cout << "multiply: " << compute_x_y(x, y, multiply) << std::endl; // multiply: 10

	// 無捕獲的lambda可以轉換爲同類型的函數指針
	auto sum = [](int x, int y)->int { return x + y; };
	std::cout << "sum: " << compute_x_y(x, y, sum) << std::endl; // sum: 7

	getchar();
	return 0;
}

5.重載了函數調用運算符的類(該類的對象又稱爲:函數對象或仿函數)
(1)函數對象:就是一個重載'()'運算符的類的對象。這樣就可以直接使用‘對象名()’的方式,這跟調用函數一樣,所以稱謂函數對象。函數對象(function object)是一個程序設計的對象允許被當作普通函數來調用。C++函數對象實質上是運算符“()”(操作符)重載。
(2)函數對象:
【1】函數對象是指該對象具備函數的行爲;
【2】函數對象,是通過()函數調用運算符聲明得到的,然後便能通過函數方式來調用該對象了;
【3】()函數調用運算符可以定義不同參數的多個重載函數;
【4】()函數調用運算符只能通過類的成員函數重載,不能通過全局函數;
【5】函數對象用於在工程中取代函數指針。

(3)函數對象與普通函數區別
函數對象,可以封裝自己的成員以及其它函數,所以能夠更好的面向對象。
普通函數,往往只具備邏輯關係,並且沒有固定的成員,因爲普通函數一被調用完後,裏面的內容便被摧毀了,除非使用全局變量,但是全局變量又不具備封裝性。
(4)Demo

#include <iostream>

using namespace std;

class Functor
{
public:
	int operator()(int a, int b)
	{
		return a < b;
	}
};

int main()
{
	Functor f;
	int a = 5;
	int b = 7;
	int ans = f(a, b);
}

6.    Lamada表達式
6.1、定義
Lambda函數,又可以稱爲Lambda表達式或者匿名函數。在C++11中加入標準。定義形式如下:
                                 [captures list] (parameters list) -> return type { function body}
captures list(捕獲列表),是一個lambda所在函數定義的局部變量的列表(通常爲空);
parameters list,爲匿名函數參數列表,當匿名函數沒有參數時,可以省略。
->return type,指定匿名函數返回值類型,可以忽略,c++11的特性,可以自動類型推導。
function body,部分爲函數體,包括一系列語句
除捕獲列表外,參數列表、函數體與普通函數一樣。返回值類型,必須 使用尾置返回來指定返回類型;尾置返回類型跟在形參列表後面以一個->符號開頭,爲了表示函數真正的返回類型跟在形參列表之後,我們在本應該出現返回類型的地方放置一個auto。

bool func1(int i) { return i % 3 == 0; }
//函數func1()對應的lambda表達式爲:
auto func2 = [](int x) -> bool { return x % 3 == 0; };
//省略返回值類型
auto func3 = [](int x) { return x % 3 == 0; };

6.2、Lambda函數捕獲列表

與普通函數最大的區別是,Lambda函數還可以通過捕獲列表訪問一些上下文中的數據。具體地,捕捉列表[]中變量,可以被Lambda函數使用。

下面是各種捕獲選項:
[] :  不捕獲任何變量
[&] :捕獲外部作用域中所有變量,並作爲引用在匿名函數體中使用
[=]: 捕獲外部作用域中所有變量,並拷貝一份在匿名函數體中使用
[x, &y]:x按值捕獲, y按引用捕獲
[&, x]:  x按值捕獲. 其它變量按引用捕獲
[=, &y]:y按引用捕獲. 其它變量按值捕獲
[this] :捕獲當前類中的this指針,如果已經使用了&或者=就默認添加此選項

6.3、Lambda函數的優點/作用
(1)定義位於使用的地方的附近,Lambda是理想的選擇,因爲其定義和使用在同一個地方進行。
(2)簡潔,與函數對象相比,Lambda函數不需要定義一個類,可以在其它函數內部定義。
(3)效率,函數指針方法阻止了內聯,因爲編譯器不會內聯其地址被獲取的函數。而函數符和Lambda函數通常不會阻止內聯。
(4)功能,Lambda可以訪問作用域內的任何動態變量,把要捕獲的變量放在中括號內。[&]讓你能夠按引用訪問所有動態變量。

補充:謂詞函數與可調用對象:
接受一個參數的函數,叫做一元函數,如果一元函數返回布爾值,則該函數成爲一元謂詞;這種函數可供STL算法進行判斷。常用於find_if、remove_if以滿足相應的情況來查找或者刪除。接受兩個參數的函數爲二元函數,如果返回一個布爾值,則該函數稱爲二元謂詞;這種函數用於諸如std::sort等STL函數中,如下使用二元謂詞對存儲std::string 值的容器進行不區分大小寫的排序;二元謂詞,在判斷兩個對象時經常使用到。
但是,如果在一個算法使用中,需要更多的參數,超出了對謂詞的限制,則可以考慮lambda表達式。即多元謂詞(多個參數)的情形,我們可以用lambda表達式來充當謂詞。同理,函數、函數指針、重載了函數調用運算符的類都可以當作謂詞。

7.    標準庫function類型(C++ Primer14.8.3)
8.    標準庫bind函數(C++ Primer10.3.4)
注:7、8編程暫未遇到,有待學習。

參考:

 https://blog.csdn.net/u010984552/article/details/53634513
 http://blog.sina.com.cn/s/blog_720484f101016q04.html

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