1.1 實(shí)驗(yàn)內(nèi)容
本節(jié)內(nèi)容主要講述 c++11 模板的用法,以后的代碼中會大量的用到模板的知識丸冕。同時簡單講解迭代器的相關(guān)知識,為后面容器和算法的內(nèi)容作鋪墊。
1.2 實(shí)驗(yàn)知識點(diǎn)
模板編程
-基本語法
-模板函數(shù)
-類模板和成員模板
-模板類中的靜態(tài)成員
-typename和class
迭代器
-迭代器詳解
-迭代器種類和使用
模板的基本語法如下:
template <typename/class T>
template 告訴編譯器许饿,接下來是一個模板 ,typename
和 class
都是關(guān)鍵字帘营,在這里二者可以互用沒有區(qū)別檩奠。在< >
中 T 叫做模板形參沛简,一旦模板被實(shí)例化,T 也會變成具體的類型瓦糟。接下來,我們看一個例子赴蝇。
模版函數(shù)
代碼實(shí)例:
template <typename T>
T add(const T lva ,const T rva)
{
T a ;
a = lva + rva ;
return a;
}
這是一個模板函數(shù)的簡單實(shí)例菩浙,所有模板函數(shù)在開始都需要 template 語句,以告訴編譯器這是一個模板和參數(shù)等必要信息扯再,當(dāng)然里面的 T 可以取任意你喜歡的名字 芍耘,模板參數(shù)個數(shù)也是任意更換的。 還要提醒的一點(diǎn)是:template <typename T1 ,typename T2 = int>
函數(shù)模板是支持默認(rèn)參數(shù)的熄阻,T1 斋竞、T2順序在默認(rèn)情況下是可以任意的,不用嚴(yán)格按照從右到左的順序秃殉。
然后就是使用了坝初,我們可以寫出add(1,2) 這樣的函數(shù),也可以寫出add(2.5,4.6)這樣的函數(shù),向 add 函數(shù)提供參數(shù)時钾军,編譯器會自動分析參數(shù)的類型鳄袍,然后將所有用到 T 定義的換成相對性的類型,以上的兩個函數(shù)在編譯期間會生成
int add(const int lva ,const int rva)
{
int a ;
a = lva + rva ;
return a;
}
double add(const double lva ,const double rva)
{
double a ;
a = lva + rva ;
return a;
}
這樣的兩個具體函數(shù)吏恭。如果我們使用add(1,2.0)是會報(bào)錯的拗小,編譯器無法找到add(int,double)。大家可以自己分析一下為什么樱哼。
類模版
c++11 不僅支持對函數(shù)的模板化哀九,也支持對類的模板,下面來看基本的語法是怎樣的:
template <class T>
class Myclass
{
T a;
public:
T add(const T lva ,const T rva);
};
template <class T>
T Myclass<T>::add(const T lva, const T rva)
{
a = lva + rva;
return a;
}
這是一個簡單并且典型的類模板搅幅,在程序中給出模板并不能使用它阅束,還必須實(shí)例化,比如:
Myclass<int> A茄唐;
//用 int 實(shí)例化一個類A
Myclass<double> B息裸;
//用 double 實(shí)例化一個類B
當(dāng)程序編譯到這里時就會按照我們給出的類型,聲明兩組類和兩組類函數(shù)。注意呼盆,在這里我們一定要顯式給出類型 T 年扩。類模板不像是函數(shù)模板 ,函數(shù)模板會根據(jù)參數(shù)推斷類型宿亡。 當(dāng)然類模板也支持默認(rèn)參數(shù)常遂,但是類模板必須嚴(yán)格從右往左默認(rèn)化。
成員模板
模板的使用范圍是廣泛的挽荠,不僅可以用作函數(shù)模板克胳,類模板,還可以用作 class 圈匆,struct 漠另,template class 的成員。而要實(shí)現(xiàn) STL 這是我們必須掌握和使用的特性跃赚。我們先看一個簡單的例子,用上面的類改編而來:
template <class T>
class Myclass
{
public:
T a;
template <typename type_1 , typename type_2>
type_1 add(const type_1 lva ,const type_2 rva);
};
template <class T>
template <typename type_1,typename type_2>
type_1 Myclass<T>::add(const type_1 lva, const type_2 rva)
{
a = lva + rva;
return a;
}
在類的聲明中使用了一個嵌套的模板聲明笆搓。且通過作用域運(yùn)算符 :: 指出 add 是類的成員,需要注意的一點(diǎn)纬傲,有些編譯器不支持模板成員满败,而有些編譯器不支持在類外定義。我們默認(rèn)大家的編譯器都支持叹括。模板如此強(qiáng)大算墨,甚至允許我們在模板類中再建立模板類:
template <class T>
class Myclass
{
public:
T a;
template <typename type_1 , typename type_2>
type_1 add(const type_1 lva ,const type_2 rva);
template <class type_3>
class Myclass_2; // 聲明放在這里,具體定義放在類外進(jìn)行汁雷。
Myclass_2<T> C; // 定義一個Myclass_2 類 A净嘀。使用 T 進(jìn)行實(shí)例化
};
template <class T>
template <typename type_1,typename type_2>
type_1 Myclass<T>::add(const type_1 lva, const type_2 rva)
{
a = lva + rva;
return a;
}
template <class T>
template <class type_3>
class Myclass<T>::Myclass_2
{
public:
type_3 value;
type_3 sub(const type_3 a , const type_3 b) {vlaue = a - b;}
};
當(dāng)然我們暫時還用不到這樣復(fù)雜的東西,這里只是展現(xiàn)了模板的部分特性侠讯。
我們知道挖藏,在類中定義的靜態(tài)成員是存儲在靜態(tài)區(qū)中,被所有類對象共享厢漩,并不屬于某一個類所有膜眠,同樣的在模板類中的靜態(tài)成員也不會被復(fù)制多份,而是被同類實(shí)例化的類對象共享溜嗜,比如所有 int 和所有 double 的類對象宵膨,享有相互獨(dú)立的靜態(tài)變量。也可以說是編譯器生成了 int 和 double 兩個版本的類定義粱胜。
typename && class
typename
和class
是模板中經(jīng)常使用的兩個關(guān)鍵詞 ,在模板定義的時候沒有什么區(qū)別狐树。以前用的是 class焙压,后來 c++ 委員會加入了 typename。因?yàn)闅v史原因,兩個是可以通用的涯曲。對有些程序員來說野哭,在定義類模板的時候,常常使用 class 作為關(guān)鍵字幻件,增加代碼可讀性拨黔。其它則用 typename,上面的代碼大都遵循這樣的標(biāo)準(zhǔn)绰沥,但是并無強(qiáng)制規(guī)定篱蝇。但是如果二者沒有差別,為什么還要加入typename呢徽曲?c++標(biāo)準(zhǔn)委員會不會增加無用的特性零截,讓我們來看一個例子:
class Myclass{
public:
Myclass();
typedef int test; //定義類型別名
}
template <class T>
class Myclass2{
public:
Myclass2();
T::test *a // 聲明一個指向T::test類型的指針。
// typename T::test * a
}
以上的代碼沒有全部寫完秃臣,大家覺得編譯器能夠過嗎涧衙?答案是不能,因?yàn)樵?c++ 中,允許我們在類中定義一個類型別名奥此,且使用的時候和類名訪問類成員的方法一樣弧哎。這樣編譯器在編譯的時候就會產(chǎn)生二義性,它根本不知道這是一個類型還是別名稚虎,所以我們加上 typename 顯式說明出來撤嫩。當(dāng)然如果這里沒有二義性,比如Myclass ::test * a
,加上 typename 是會報(bào)錯的祥绞。此外非洲,在 class 的 STL 底層還有一個特性,用于保留模板參數(shù)蜕径,但是在 c++17 中已經(jīng)舍棄两踏,所以我們沒有講。
[](javascript:;)