組成
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;
}
後面會介紹如何實現這種可配接能力