GeekBand STL與泛型編程 第一周

1.模板觀念與函數(shù)模板

課程主要內(nèi)容

  • C++模板簡(jiǎn)介
  • 泛型編程
  • 容器
  • 進(jìn)階

C++模板簡(jiǎn)介

??generic types:泛型。type翻譯為型別奴愉。型別更加的具體。

??簡(jiǎn)單的例子:

int Max(int a, int b){
    return (a > b) ? a : b;
}

long Max(long a, long b){
    return (a > b) ? a : b;
}
...

===>

template<typename T>
T Max(T a, T b){
    return (a > b) ? a : b;
}

??在這個(gè)函數(shù)中铁孵,T是一個(gè)abstract type锭硼,generic type,不是一個(gè)具體的類(lèi)型蜕劝。

兩種類(lèi)模板

  • 類(lèi)模板(Class template)
  • 函數(shù)模板(Function template)

??模板聲明的時(shí)候檀头,并未給出函數(shù)或類(lèi)的完整定義。只是提供了一個(gè)語(yǔ)法框架岖沛。

??模板的實(shí)例化是從模板構(gòu)建出一個(gè)真正的函數(shù)或類(lèi)的過(guò)程暑始,指定T真正型別的時(shí)候。

實(shí)例化(instantiation)

  • 顯式實(shí)例化婴削,在代碼中明確指定
  • 隱式實(shí)例化廊镜,由編譯器推導(dǎo)

C++函數(shù)模板

??是指參數(shù)化的一族函數(shù)(不止一個(gè))。

class 和 typename馆蠕,在用作定義型別參數(shù)時(shí)期升,在語(yǔ)法上沒(méi)有區(qū)別,但是在語(yǔ)義上有區(qū)別互躬,建議使用typename播赁。但是不能使用struct。

??在使用Max模板函數(shù)時(shí)吼渡,不能使用不同型別的參數(shù)來(lái)調(diào)用容为。

??用具體型別代替模板參數(shù)T的過(guò)程就叫做實(shí)例化,從而產(chǎn)生了一個(gè)模板實(shí)例寺酪。

模板被編譯了兩次

  • 沒(méi)有實(shí)例化之前坎背,編譯器會(huì)檢查語(yǔ)法是否有錯(cuò)誤。
  • 實(shí)例化期間寄雀,編譯器會(huì)檢查調(diào)用是否合法得滤。

參數(shù)推導(dǎo)

  • 模板參數(shù)是由傳遞給模板函數(shù)的實(shí)參決定的。
  • 不允許自動(dòng)型別轉(zhuǎn)換盒犹,每個(gè)T必須嚴(yán)格匹配懂更。
Max(1, 2.0);

===>

Max(static_cast<double>(1), 2.0);//將1轉(zhuǎn)換為double

Max<double>(1, 2.0);//編譯器認(rèn)為1為double

函數(shù)模板重載

??函數(shù)模板也可以像普通函數(shù)一樣被重載。普通函數(shù)可以和模板函數(shù)同同時(shí)存在(名稱(chēng)一樣)急膀,當(dāng)調(diào)用即符合普通函數(shù)的調(diào)用沮协,又符合模板函數(shù)時(shí),優(yōu)先調(diào)用普通函數(shù)卓嫂。

??所有的重載版本的聲明必須位于他們被調(diào)用位置之前慷暂。

2.類(lèi)模板與操作符重載

類(lèi)模板

??類(lèi)通過(guò)參數(shù)泛化,從而構(gòu)建出一族不同型別的類(lèi)實(shí)例晨雳。

??類(lèi)模板實(shí)參可以是某一型別或常量(僅限int或enum)行瑞,而且可以帶默認(rèn)值奸腺。

一個(gè)例子

const std::size_t DefaultStackSize = 1024;
template<typename T, std::size_t n = DefaultStackSize>
class Stack{
public:
    void Push(const T cosnt& element);
    int Pop(T& element);
    int Top(T& element) cosnt;
private:
    std::vector<T> m_Members;
    std::size_t m_nMaxSize = n; //n是編譯時(shí)的常量血久,n可以有默認(rèn)值
};

類(lèi)模板的聲明

??在類(lèi)模板內(nèi)部洋机,T可以像其他型別一樣,定義變量和成員函數(shù)洋魂。

??除了Copy constructor之外绷旗,如果在類(lèi)模板中需要使用到類(lèi)本身,如operator=副砍,應(yīng)該使用完整的定義(Stack<T, n>),而不能省略型別T衔肢。

Stack<T>& operator= (Stack<T, n> const &)

類(lèi)模板的實(shí)現(xiàn)

template<typename T, std::size_t nMaxSize>
void Stack<T, nMaxSize>::Push(const T cosnt& element){ ... }

類(lèi)模板的特化
??允許對(duì)一個(gè)類(lèi)模板的某些模板參數(shù)型別做特化。

??特化的作用或好處

  • 對(duì)于某種特殊的型別豁翎,可以做一些特別的優(yōu)化或提供不同的處理方式角骤。
  • 避免在實(shí)例化類(lèi)模板時(shí)引起一些可能產(chǎn)生的詭異行為。

??特化一個(gè)類(lèi)需要特化其所有參數(shù)化的成員函數(shù)心剥。

template<>
class Stack<std::wstring>{ ... };

??特化后可以添加新的成員函數(shù)邦尊,也可以改為使用list來(lái)存儲(chǔ)Stack的內(nèi)部實(shí)現(xiàn)。

偏特化

類(lèi)模板被定義為:

template <typename T1, typename T2> 
class MyClass{ ... };
  • 偏特化為同樣類(lèi)型:
template <typename T> class MyClass<T, T> { ... };
  • 偏特化部分模板參數(shù)為指定型別:
template <typename T> class MyClass<T, int> { ... };
  • 偏特化為指針:
template <typename T1, typename T2> 
class MyClass<T1*, T2*>{ ... };
使用 原型
MyClass<int, float> obj; MyClass<T1, T2>
MyClass<float, float> obj; MyClass<T, T>
MyClass<float, int> obj; MyClass<T, int>
MyClass<int, float> obj; MyClass<T1, T2>

??如果不止一個(gè)偏特化同等程度地能夠匹配某個(gè)調(diào)用优烧,那么該調(diào)用具有二義性蝉揍,編譯會(huì)報(bào)錯(cuò)。

使用 原型
MyClass<int, int> obj; Error matches MyClass<T, T> and MyClass<T, int>
MyClass<int, int> obj; Error matches MyClass<T, T> and MyClass<T1, T2>

默認(rèn)模板實(shí)參

??類(lèi)似于函數(shù)的默認(rèn)參數(shù)畦娄,對(duì)于類(lèi)模板而言也可以定義其模板參數(shù)的默認(rèn)值又沾,這些值就叫做默認(rèn)模板參數(shù)。

C++操作符重載

  • 不可以用operator定義一種新的操作符
  • 對(duì)于內(nèi)置型別熙卡,不能再用operator重載
  • 可重載為非靜態(tài)成員函數(shù)或靜態(tài)全局函數(shù)杖刷,如果該全局函數(shù)需要訪問(wèn)類(lèi)的private和protected成員,則需要聲明為friend驳癌。
  • 除了operator=滑燃,所有其他操作符重載均可以被子類(lèi)繼承。

3.泛型編程(Generic Programming)

概觀

??泛型編程是一種思想颓鲜,是一種編程方法表窘。在不同的語(yǔ)言表現(xiàn)方式不一樣,在C++中使用模板的方式表現(xiàn)出來(lái)灾杰。

關(guān)聯(lián)特性 Traits

什么是traits蚊丐,以及為什么使用traits熙参?

template<typename T>
T Sigma(const T* begin, const T* end){
    T total = T();
    while(end != begin){
        total += *begin++;
    }
    return total;
}
char str[] = "abc";
int length = strlen(str);
char* p = str;
char* e = str + length;
printf("Sigma(str) = %d\n", Sigma(p, q)); //得到的結(jié)果溢出艳吠。    

運(yùn)行結(jié)果(溢出):

Sigma(str) = 38

??為每個(gè)Sigma函數(shù)的參數(shù)型別創(chuàng)建一種關(guān)聯(lián)(association),關(guān)聯(lián)的型別就是用來(lái)存儲(chǔ)Sigma結(jié)果的型別孽椰。

??這種關(guān)聯(lián)可以看做是型別T的一種特性(characteristic of the type T)昭娩,此種型別可以稱(chēng)作T的trait凛篙。

??Trais可以實(shí)現(xiàn)為模板類(lèi),association則是針對(duì)每個(gè)具體型別T的特化栏渺。

template<typename T> class SigmaTraits{};
template<> class SigmaTraits<char>{
    public: typedef int ReturnType;
};
template<> class SigmaTraits<short>{
    public: typedef int ReturnType;
};
...

修改后的Sigma函數(shù):

template<typename T>
typename SigmaTraits<T>::ReturnType Sigma(const T* begin, const T* end){
    typedef SigmaTraits<T>::ReturnType ReturnType;
    ReturnType total = ReturnType();
    while(end != begin){
        total += *begin++;
    }
    return total;
}

修改后的執(zhí)行結(jié)果:

Sigma(str) = 294

??雖然此時(shí)傳入?yún)?shù)T的型別是char呛梆,但是返回類(lèi)型是int。原因就是使用了Traits磕诊。

迭代器

??迭代器是指泛化的指針填物,迭代器本身是一個(gè)對(duì)象,指向另外一個(gè)(可以被迭代的)對(duì)象霎终。

??在STL中迭代器是容器和算法之間的接口滞磺。

基本思想

  • 分離算法和容器,不需要相互依賴(lài)莱褒。
  • 粘合算法和容器击困,使得一種算法的實(shí)現(xiàn)可以運(yùn)用到多種不同的容器上。
  • 每種容器都有其對(duì)應(yīng)的迭代器广凸。

4.容器(上)

Vector

??Vector是一種可以存放任意型別的動(dòng)態(tài)數(shù)組阅茶,連續(xù)的內(nèi)存空間。

#include<vector>//使用的時(shí)候谅海,不要加.h

訪問(wèn)vector的元素:

  • vector::at() //有數(shù)組越界檢查脸哀,效率低。
  • vector::operator[] //不檢查扭吁,效率高企蹭。

刪除vector的元素:

  • clear:清除整個(gè)vector
  • pop_back:彈出vector尾部元素
  • erase:刪除vector某一位置元素
v.erase(
    std::remove_if(
        v.begin(),
        v.end(),
        ContainsString(L"C++")
    ),
    v.end());

??std::remove_if函數(shù)返回了一個(gè)迭代器,需要?jiǎng)h除的元素的位置智末,remove_if函數(shù)需要一個(gè)條件函數(shù)谅摄,條件函數(shù)是一個(gè)派生自std::unary_function的一個(gè)仿函數(shù),返回true或false來(lái)決定該元素是否是否會(huì)被刪除系馆。

Deque

??Deque是一種可以存放任意型別的雙向隊(duì)列送漠。

??Deque提供的函數(shù)與vector類(lèi)似,新增了兩個(gè)函數(shù):

  • push_front:在頭部插入一個(gè)元素
  • pop_front:在頭部彈出一個(gè)元素

List

??List是一種可以存放任意型別的雙向鏈表(doubly linked list)由蘑。內(nèi)存中地址不連續(xù)闽寡。

List的優(yōu)勢(shì):

  • List的優(yōu)勢(shì)在于其彈性,可以隨意插入和刪除元素尼酿,僅僅改變節(jié)點(diǎn)前項(xiàng)和后項(xiàng)的鏈接爷狈。
  • 對(duì)于插入、刪除和替換等裳擎,效率極高涎永。
  • 通常只改變鏈接,沒(méi)有元素復(fù)制。

List的劣勢(shì):

  • 只能以連續(xù)的方式存取List中的元素羡微。
  • 對(duì)于查找谷饿、隨機(jī)存取等元素定位,效率低妈倔。

splice

list::splice實(shí)現(xiàn)list拼接的功能博投。將源list的內(nèi)容部分或全部元素刪除,拼插入到目的list盯蝴。

函數(shù)有以下三種聲明:

void splice ( iterator position, list<T,Allocator>& x );

void splice ( iterator position, list<T,Allocator>& x, iterator i );

void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last );

函數(shù)說(shuō)明:在list間移動(dòng)元素:

  • 將x的元素移動(dòng)到目的list的指定位置毅哗,高效的將他們插入到目的list并從x中刪除。
  • 目的list的大小會(huì)增加捧挺,增加的大小為插入元素的大小黎做。x的大小相應(yīng)的會(huì)減少同樣的大小。
  • 前兩個(gè)函數(shù)不會(huì)涉及到元素的創(chuàng)建或銷(xiāo)毀松忍。第三個(gè)函數(shù)會(huì).
  • 指向被刪除元素的迭代器會(huì)失效蒸殿。

參數(shù):

  • position:目的list的位置,用來(lái)標(biāo)明 插入位置鸣峭。
  • x :源list宏所。
  • first,last:x里需要被移動(dòng)的元素的迭代器。區(qū)間為[first, last)摊溶,包含first指向的元素爬骤,不包含last指向的元素。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莫换,一起剝皮案震驚了整個(gè)濱河市霞玄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拉岁,老刑警劉巖坷剧,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喊暖,居然都是意外死亡惫企,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)陵叽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狞尔,“玉大人,你說(shuō)我怎么就攤上這事巩掺∑颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵胖替,是天一觀的道長(zhǎng)研儒。 經(jīng)常有香客問(wèn)我豫缨,道長(zhǎng),這世上最難降的妖魔是什么殉摔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮记焊,結(jié)果婚禮上逸月,老公的妹妹穿的比我還像新娘。我一直安慰自己遍膜,他們只是感情好碗硬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著瓢颅,像睡著了一般恩尾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挽懦,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天翰意,我揣著相機(jī)與錄音,去河邊找鬼信柿。 笑死冀偶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渔嚷。 我是一名探鬼主播进鸠,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼形病!你這毒婦竟也來(lái)了客年?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤漠吻,失蹤者是張志新(化名)和其女友劉穎量瓜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體途乃,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榔至,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了欺劳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唧取。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖划提,靈堂內(nèi)的尸體忽然破棺而出枫弟,到底是詐尸還是另有隱情,我是刑警寧澤鹏往,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布淡诗,位于F島的核電站骇塘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏韩容。R本人自食惡果不足惜款违,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望群凶。 院中可真熱鬧插爹,春花似錦、人聲如沸请梢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)毅弧。三九已至气嫁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間够坐,已是汗流浹背寸宵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留元咙,地道東北人邓馒。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蛾坯,于是被迫代替她去往敵國(guó)和親光酣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容