進階篇_STL詳解(函式模板特化,類别範本特化,用模板實現自己的通用演算法)
STL ~= 容器 + 演算法 + 迭代器。容器用於容納資料,演算法用於處理資料,迭代器像膠水一樣將容器和演算法緊密地結合在一起。演算法通過迭代器來定位和操控容器中的元素,事實上,每個容器都有自己的迭代器,只有容器自己才知道如何訪問自己的元素,這使得迭代器就像一個指向容器中元素的普通指標一樣。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//工資統計,計算收入大於1000的員工人數
int main()
{
vector<int> vecSalary;
int put;
do
{
cin>>put;
if(0 == put)
break;
vecSalary.push_back(put);
}while(true);
int total = count_if(vecSalary.begin(), vecSalary.end(), bind2nd(greater<int>(), 1000)); //count_if:返回區間中滿足指定條件的元素數目。
cout<<total<<endl;
return 0;
}
容器vector的使用不像陣列那樣固定分配記憶體,其可以根據使用者的輸入動態地增長,保證記憶體空間的合理利用,又可以讓程式具有很大的可擴張性,處理很大範圍內的資料。由此可得到STL的主要幾個好處:封裝很多常用的資料結構(容器),提供很多常用的通用演算法(演算法),除錯程式更加安全和方便,支援跨平臺(使用STL的C++程式碼可以輕鬆地移植到其他平臺上)。模板是實現程式碼重用的一種重要機制,它可以實現型別的引數化,把型別定義為引數,而STL正是藉助模板的威力建構起來的。
函式模板
如果說把函式比作一個箱子,每個箱子都是專用的(實現具體的不同功能),那函式模板就是一個萬能箱子,它可以用來裝各種東西,處理各種型別的資料。比如當編譯器發現一個函式模板的呼叫後,將根據實參的實際資料型別來確認是否匹配函式模板中對應的形參,然後生成一個過載函式,稱該過載函式為模板函式。根據引數型別的不同,一個函式模板可以隨時變成各種不同的過載函式,從而實現對各種資料型別的處理。函式模板可以用來建立一個通用功能的函式,以支援各種不同的資料型別,簡化過載函式的設計。函式模板的宣告與使用如下:
#include <iostream>
using namespace std;
//模板函式範例
template <typename T> //type理解為模板函式中的一個引數,代表抽象的資料型別
T max(const T a, const T b)
{
return a>b ? a : b;
}
int main()
{
int a = 10;
int b = 20;
int c = std::max<int>(a, b); //注意寫法,不加std::,會error
cout<<c<<endl; //output: 20
float aa = 0.3;
float bb = 0.4;
float cc = std::max(aa, bb); //max<float>的<...>不寫編譯器會自動分析生成相應的過載函式,但是有時候必須要指明型別引數以滿足特殊需求,比如max<string>
cout<<cc<<endl; //output: 0.4
string aaa = "abcd";
string bbb = "cde";
string ccc = std::max(aaa, bbb);
cout<<ccc<<endl; //output: cde,這裡輸出cde,不是返回最長的而是返回字元較大的,所以如果需要應該對模板函式進行特化,實現特定型別的模板函式
return 0;
}
特化模板函式,實現特定型別的string模板函式,希望返回最長的字串:
#include <iostream>
using namespace std;
//特化函式模板string範例
template <typename T> //普通函式模板
T max(const T a, const T b)
{
return a>b ? a : b;
}
template <> //特化string的函式模板
string max<string>(const string a, const string b) //注意這裡及以上的寫法格式
{
return a.size()>b.size() ? a : b;
}
int main()
{
int a = 5;
int b = 4;
float c = 5.3;
float d = 4.4;
cout<<std::max(a, b)<<endl<<std::max(c, d)<<endl; //output: 5 5.3
string x = "chen";
string y = "aisda";
cout<<std::max(x, y)<<endl; //用普通函式模板output: cde,返回字元較大的
cout<<std::max<string>(x, y)<<endl; //用特化函式模板output: chen,返回字串最長的
return 0;
}
類别範本
#include <iostream>
using namespace std;
//特化類别範本範例
//定義一個比較兩個數的類别範本compare<T>
template <typename T> //typename所定義的識別符號實際上就是類别範本的引數,模板引數可以是一個可以是多個
class compare
{
public:
compare(T a, T b)
: m_a(a), m_b(b)
{
}
public:
T min()
{
return m_a > m_b ? m_b : m_a;
}
T max()
{
return m_a > m_b ? m_a : m_b;
}
private:
T m_a;
T m_b;
};
int main()
{
compare<int> intcompare(2, 3);
cout<<intcompare.max()<<" > "<<intcompare.min()<<endl;
compare<float> floatcompare(2.2, 4.4);
cout<<floatcompare.max() <<" > "<<floatcompare.min()<<endl;
return 0;
}
/*output: 3 >2 4.4 > 2.2*/
模板的例項化
模板的例項化分為:隱式例項化和顯式例項化。
compare<int> intcompare(2, 3); //隱式例項化
大多數都採用隱式例項化,具體的顯式例項化如果需要時自行再查,注意的是顯式例項化類時,所有的類成員也必須例項化。用模板實現自己的通用演算法
#include <iostream>
using namespace std;
/*軟體誰集中,通常有一個撤銷undo和恢復redo的通用功能*/
/*動作容器模板類,使用T作為模板引數*/
template <class T>
class actioncontainer
{
public:
actioncontainer()
{
m_nredo = 0;
m_nundo = 0;
}
void add(T value); //向容器中新增新動作
T redo(); //恢復上一步動作
T undo(); //撤銷上一步動作
private:
int m_nredo;
int m_nundo;
const static int ACTION_SIZE = 5;
T m_redoAction[ACTION_SIZE]; //使用陣列記錄恢復和撤銷的動作,陣列元素的型別也是模板引數,它在類别範本例項化時才確定
T m_undoAction[ACTION_SIZE];
};
/*模板類的成員函式實現*/
//向容器中新增動作,這裡的T可以是一個基本資料型別,也可以是一個自定義型別
template <class T>
void actioncontainer<T>::add(T value)
{
//判斷容器中的動作數目是否超過容器的容量
if(m_nundo >= ACTION_SIZE)
{
m_nundo = ACTION_SIZE - 1;
for(int i=0; i<ACTION_SIZE; ++i)
m_undoAction[i] = m_undoAction[i+1]; //將容器中已有的動作前移一個位置
}
//將新動作新增到容器中
m_undoAction[m_nundo++] = value;
}
//撤銷上一步動作
template <class T>
T actioncontainer<T>::undo()
{
m_redoAction[m_nredo++] = m_undoAction[--m_nundo]; //將撤銷的動作複製到恢復陣列中
return m_undoAction[m_nundo]; //返回撤銷的動作
}
//恢復上一步動作
template <class T>
T actioncontainer<T>::redo()
{
m_undoAction[m_nundo++] = m_redoAction[--m_nredo]; //將撤銷的動作複製到恢復陣列中
return m_redoAction[m_nredo]; //返回撤銷的動作
}
int main()
{
actioncontainer<int> intaction; //定義一個int型別的動作容器,這樣這個動作容器就可以容納int型別的資料
intaction.add(1); //向容器中新增新的動作,也就是整數
intaction.add(2);
intaction.add(3);
intaction.add(4);
int nundo = intaction.undo(); //撤銷上一步動作,這時,nundo的值為4
nundo = intaction.undo();//再次撤銷身上一步動作,nundo的值為3
int nredo = intaction.redo(); //恢復上一步動作,這時,nredo的值為3
nredo = intaction.redo();//再次恢復身上一步動作,nredo的值為4
return 0;
}
以上程式碼定義了一個類别範本actioncontainer<T>,這個類可以容納動作(add)並且能夠進行撤銷(undo)和恢復(redo)動作。在這個模板類的內部,使用了兩個陣列來分別記錄撤銷和恢復的動作。這裡的動作實際上是廣義上的一種資料型別,它可以是一個基本資料型別比如int float,也可以是自己定義的資料型別,這樣就使得這個動作容器具有廣泛的通用性,可以處理各種資料型別。在這個動作容器類别範本actioncontainer<T>中,還定義了它的成員函式,用於操作這個容器中的資料,其中包括新增新的動作到容器中、撤銷或恢復動作等。當然,這裡成員函式同樣是對抽象的模板引數進行操作,其中並不涉及具體的資料型別,也就是說,這些操作與具體的資料型別無關。
相關文章
- 模板函式的特化函式
- C++知識點57——類别範本(2、類别範本的區域性特化與預設模板實參)C++
- c++函式模板和類别範本C++函式
- 類别範本 單例模板單例
- 【C++ 泛型程式設計01:模板】函式模板與類别範本C++泛型程式設計函式
- C++之函式模板與類别範本的區別(三)C++函式
- 模板顯式、隱式例項化和(偏)特化、具體化的詳細分析
- c++中模板_類别範本的宣告和定義C++
- c++11-17 模板核心知識(二)—— 類别範本C++
- c++泛型程式設計中函式模板過載和模板特化同時存在時的查詢規則C++泛型程式設計函式
- C++ 單例類别範本(詳解)C++單例
- 母函式詳解和史上最通用最高效的母函式模板函式
- c++佇列類别範本的實現C++佇列
- c++類别範本成員函式報錯C++函式
- C#模擬C++模板特化對型別的值的支援C#C++型別
- 資料結構初階--棧和佇列(講解+類别範本實現)資料結構佇列
- 資料結構初階--單連結串列(講解+類别範本實現)資料結構
- 陣列類别範本陣列
- 進階篇_STL中通用演算法處理資料演算法
- 類别範本及其成員函式的定義及注意事項函式
- 類别範本的常見用法
- 資料結構初階--雙向迴圈連結串列(講解+類别範本實現)資料結構
- C++ 類别範本的寫法C++
- const char*的全特化
- pua 八股類别範本
- C++ Templates (2.1 類别範本Stack的實現 Implementation of Class Template Stack)C++
- 非型別的類别範本引數型別
- c++中的特化問題C++
- 【C++進階筆記】(1)函式模板的宣告及使用C++筆記函式
- 函式模板函式
- C++關於DLL匯出模板類和模板函式C++函式
- 隱藏在 SDK 中的單例類别範本單例
- 【演算法學習】數學專題 有理數類别範本演算法
- 【C++】 59_類别範本深度剖析C++
- Smarty 模板函式函式
- 進階篇_STL中的容器
- C++模板函式實現型別推導C++函式型別
- 【C++】 61_智慧指標類别範本C++指標