C++ STL基本概念 學習筆記

組成

1.容器(containers)

2.算法  (algorithms)

3.迭代器 (iterators)

4.仿函數  (functors)

5.配接器 (adapters)

6.空間配置器  (allocators)

1. 容器

序列式容器:元素的可序(ordered), 有序(sorted)

關聯式容器:

array: 大小固定的序列容器,保存了一個以嚴格的線性順序排列的特定數量的元素。

各種數據結構:vector, list, deque, set, map, 用來存放數據。 從實現來看,是一種calss template

2. 算法

各種常見的算法,sort, search,copy, erase, 從實現來看,是一種function template

3. 迭代器

扮演容器與算法之間的膠合劑,是所謂的泛型指針。從實現的角度看,是一種將operator*,operator->, operator++, operator--等指針相關操作重載的class template. 所有STL容器都帶有自己專屬的迭代器。

4.仿函數

行爲類似函數,可以作爲算法的某種策略。

5. 配接器

一種用來修飾容器,仿函數,或者迭代器接口的東西。

例如STL提供的queue和stack,看似容器,實際是一種容器配接器,因爲他們的底層完全藉助deque,所有底部的操作都由deque提供。

6. 空間配置器

負責空間配置與管理。

-----------------------------------------------------------分割線----------------------------------------------------------------

臨時對象的產生與應用:

臨時對象是一種無名對象,在型別名稱之後直接加括號,並可指定初值。例如shape(3,5),int(8).意義相當於調用相應的構造函數且不指定對象名。STL中常用於仿函數與算法的搭配上:(這一段暫時沒理解,後面應該會講到。

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

template<typename T>   // 定義一個模板類 
class print
{
	public:
	void operator()(const T& elem)  // 運算符重載 
	{
		cout << elem << endl;
	}
};    //end

int main(int argc, char *argv[])
{
    int a[6] = {0,1,2,3,4,5};
	vector<int> iv(a, a+6);   // a是第一個元素的地址,a+6超尾, c++STL中的概念
	// print<int>()一個臨時對象
	for_each(iv.begin(), iv.end(), print<int>());    
	return 0;
}

STL中的區間表示方法:
任何一個STL算法,都需要獲得由一對迭代器(泛型指針)所表示的區間,用以表示操作範圍,這一對迭代去所表示的是一個左閉右開的區間[first, last),這種表示方法,能簡化程序的設計。

例如定義一個庫函數find()

//例如設計一個find庫函數
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value) // InputIterator 
{
	while(first!=last && *first!=value)
	{
		first++
	} 
	return first;    // 如果沒找到,first指向的是最後一個元素的後一個位置 
	// c++中超尾的概念 
} 

此外, 上面用到的for_each也應用到了這種區間表示方法:

// 例如對於for_each的設計
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)  // InputIterator迭代器 
{
	for( ; first!=last; first++)
	{
		f(*first)
	}
	return f;
}

應爲上述的兩個過程都用到了迭代器的知識,在之前看c++的時候,沒有理解迭代器,現在好像理解了它的作用是什麼:

回顧一下之前的c++迭代器:

一個迭代器是一個指針,指向對象的一個元素,一個迭代器可以用來訪問對象的所有元素,例如用一個指向數組元素的指針可以訪問數組的所有元素。迭代器是編寫c++通用算法的基礎概念,例如STL總的copy函數的實現:

// STL中copy的實現:
template<class iterator>
void copy(iterator begin, iterator end, iterator to)
{
	// begin 迭代器的起始
	// end 迭代器的終止
	// to copy數據的目的地
	while(begin!=end)
	{
		*to = *begin;
		begin++;
		to++;
	} 
} 

爲了簡化迭代器的開發和基於迭代器的通用算法的分類,c++的STL定義了5中迭代器,輸入,輸出,前向,雙向,隨機訪問,所有迭代器都具備操作符==,!=, *操作符,部分具有++,--操作符。

例如,定義一個線性表arrayList的迭代器:

// 迭代器的實現
class iterator
{
	protected:
	T* position; 
	
	public:
	typedef bidirectional_iterator_tag iterator_category;
	typedef T value_type;
	typedef ptrdiff_t difference_type;
	typedef T* pointer;
	typedef T& reference;
	
	// 構造函數
	iterator(pointer thePosition = 0)
	{
		position = thePosition;
	}
	
	// 解引用操作符
	T& operator*() const   // 只讀函數 
	{
		return *position;
	} 
	T* operator->()        // 只讀函數 
	{
		return &(*position);
	}
	
	// 重載迭代器的++運算符
	// 前綴+
	iterator& operator++()
	{
		position += 1;
		return *this;
	}
	// 後綴+
	iterator operator++(int dummy)  // 僞參數
	{
		iterator old = position;
		position++;
		return old;
	} 
	
	// 重載--運算符
	// 前綴-
	iterator& operator--()
	{
		position -= 1;
		return *this;
	}
	// 後綴- 
	iterator operator--()
	{
		iterator old = position;
		position++;
		return old;
	}
	
	// 重載!= ,==
	bool operator!=(const iterator right) const
	{
		return position != right.position;
	}
	
	bool operator==(const iterator right) const
	{
		return position == right.position;
	} 
	 
}

function call操作符(operator( ) ):

在之前學習函數特性的時候,博客《c++ 函數指針》,c++ primer中介紹了函數指針,如需將函數作爲參數傳遞,可以通過函數指針,但是函數指針有缺點,它無法持有自己的狀態,也無法達到組件技術中的可適配性(也就是無法再將某些條件加諸其上而改變其狀態,(python裝飾器實現的便是這一功能))。STL算法中所接受的條件( 用以改變狀態的條件 )都是以仿函數的形式呈現。所謂仿函數(functor)使用起來和函數一樣,如果對某個類進行operator()重載,他就成爲一個仿函數。

所以這裏可以對前面的for_each的第三個參數進行理解,他接受的實際是一個仿函數,這個仿函數相當於條件,可以改變for_each的狀態:

再把代碼複製過來,就很容易理解了:print類進行了operator()重載,所以他是一個仿函數

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

template<typename T>   // 定義一個模板類 
class print
{
	public:
	void operator()(const T& elem)  // 運算符重載 
	{
		cout << elem << endl;
	}
};    //end

int main(int argc, char *argv[])
{
    int a[6] = {0,1,2,3,4,5};
	vector<int> iv(a, a+6);   // a是第一個元素的地址,a+6超尾, c++STL中的概念
	// print<int>()一個臨時對象
	for_each(iv.begin(), iv.end(), print<int>());    
	return 0;
}

再看兩個例子:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

template<typename T> 
class plus   // plus()成爲一個仿函數 
{
	T operator()(const T& x, const T& y)   // 重載() 
	{
		return x+y;
	}
};

template<typename T>
class minus   // minus()成爲一個仿函數 
{
	T operator()(const T& x, const T& y)
	{
		return x-y;
	}
};


int main(int argc, char *argv[])
{
    // 仿函數對象
	plus<int> plusobj;
	minus<int> minusobj;
	
	cout << plusobj(12, 5) << endl;   // 臨時對象 
	cout << minusobj(12, 5) << endl;
	
	// 和普通函數的用法一樣
	cout << plus<int>()(12, 5) << endl;   // 臨時對象 
	cout << minus<int>()(12, 5) << endl;
	 
	return 0;
}

後面會介紹如何實現這種可配接能力

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