新聞中心
在前面我們介紹了《C++之函數(shù)模板》

今天我們繼續(xù)來(lái)介紹模板的另外一種形式:類模板。
與模板函數(shù)相似,類也可以被一種或多種類型參數(shù)化,標(biāo)準(zhǔn)庫(kù)中的容器類就是一個(gè)具有這種特性的典型例子。
類模板的聲明
我們通過(guò)一段例子代碼了解一下類模板的聲明:
// 類模板聲明
template
class MyClass{
public:
T getT();
void setT(T t);
private:
T t;
};
// 類成員函數(shù)實(shí)現(xiàn)
template
T MyClass::getT() {
return t;
}
template
void MyClass::setT(T t) {
this->t = t;
}
int main(int argc, char* argv[]) {
// 類模板使用
MyClass myClass;
myClass.setT(10);
std::cout << "myClass:" << myClass.getT() << std::endl;
return 0;
} 首先也是使用關(guān)鍵字template和關(guān)鍵字typename對(duì)類模板進(jìn)行聲明,當(dāng)我們將一個(gè)類聲明為類模板之后,模板參數(shù)T可以像其他任何類型一樣,用于聲明成員變量和成員函數(shù)。
類模板的成員函數(shù)
通過(guò)上面的實(shí)例代碼,我們看到在類模板的聲明內(nèi)部函數(shù)時(shí)如果用到模板參數(shù)T,則不用再次使用template
也即是說(shuō)為了定義類模板的成員函數(shù),你必須指定該成員函數(shù)是一個(gè)函數(shù)模板,而且你還需要使用這個(gè)類模板的完整類型限定符。
或許你覺(jué)得每次定義類模板的內(nèi)部函數(shù)都要使用到模板聲明,當(dāng)內(nèi)部函數(shù)較多時(shí),則會(huì)產(chǎn)生非常多的不必要的聲明,此時(shí)我們可以直接在類的內(nèi)部聲明加定義同時(shí)實(shí)現(xiàn):
// 類模板聲明
template
class MyClass{
public:
// 聲明加定義
T getT(){
return t;
}
// 聲明加定義
void setT(T t){
this->t = t;
}
private:
T t;
}; 在類模板中只有那些被調(diào)用的成員函數(shù),才會(huì)產(chǎn)生這些函數(shù)的實(shí)例化代碼。對(duì)于類模板,成員函數(shù)只有在被使用的時(shí)候才會(huì)被實(shí)例化。 顯然,這樣可以節(jié)省空間和時(shí)間;另一個(gè)好處是:對(duì)于那些“未能提供所有成員函數(shù)中所有操作的”類型,你也可以使用該類型來(lái)實(shí)例化類模板, 只要對(duì)那些“未能提供某些操作的”成員函數(shù),模板內(nèi)部不使用即可。
類模板的特例化
同模板函數(shù)的特化一樣,你可以用模板實(shí)參來(lái)特化類模板,和函數(shù)模板的重載類似,通過(guò)特化類模板,我們可以優(yōu)化基于某種特定類型的實(shí)現(xiàn)。
在類模板的特化過(guò)程中有兩個(gè)步驟:
- 在類的起始處聲明一個(gè)template<>,接下來(lái)聲明用來(lái)特化類模板的類型。這個(gè)類型被用作模板實(shí)參,且必須在類名的后面直接指定。
- 進(jìn)行類模板的特化時(shí),每個(gè)成員函數(shù)都必須重新定義為普通函數(shù),原來(lái)模板函數(shù)中的每個(gè)T也相應(yīng)地被進(jìn)行特化的類型取代。
下面是一個(gè)模板類特化的例子:
// 類模板聲明
template
class MyClass{
public:
// 聲明加定義
T getT(){
return t;
}
// 聲明加定義
void setT(T t){
this->t = t;
}
private:
T t;
};
// 類模板聲明
template <>
class MyClass{
public:
// 聲明加定義
std::string getT(){
return t;
}
// 聲明加定義
void setT(std::string t){
std::cout << "調(diào)用特化類模板 setT" << std::endl;
this->t = t;
}
private:
std::string t;
};
int main(int argc, char* argv[]) {
// 類模板使用
MyClass myClass;
myClass.setT("hello word");
std::cout << "myClass:" << myClass.getT() << std::endl;
return 0;
}
模板源碼組織模式
模板源碼的組織模式有好多種,這里只介紹兩種常用的:分別是包含模式和關(guān)鍵字export的分離模式。
包含模式可以說(shuō)是最常用也是最推薦的一種模式。這種模式就是將模板類的聲明和定義都放在同一個(gè)文件中,這個(gè)文件一般是擴(kuò)展名為.hpp的文件。
下面是一個(gè)類模板聲明定義和使用分開(kāi)在不同文件的例子:
MyClass.hpp
#include
#include
// 類模板聲明
template
class MyClass{
public:
// 聲明
T getT();
void setT(T t);
private:
T t;
};
template
T MyClass::getT() {
return t;
}
template
void MyClass::setT(T t) {
this->t = t;
} 在main函數(shù)中使用模板main.cpp:
main.cpp
#include
#include
#include "MyClass.hpp"
int main(int argc, char* argv[]) {
// 類模板使用
MyClass myClass;
myClass.setT("hello word");
std::cout << "myClass:" << myClass.getT() << std::endl;
return 0;
} 很明顯,包含模式因?yàn)榘祟惸0宓亩x實(shí)現(xiàn),因而明顯增加了包含頭文件.hpp的開(kāi)銷,這會(huì)導(dǎo)致大大增加了編譯復(fù)雜程序所耗費(fèi)的時(shí)間。 然而隨著現(xiàn)代的機(jī)器性能提升,這里帶來(lái)的編譯開(kāi)銷基本可以忽略不計(jì),因此這種模式成為了使用最多的模式。
下面我們?cè)賮?lái)看看關(guān)鍵字export的分離模式。
關(guān)鍵字export的功能使用是非常簡(jiǎn)單的:在一個(gè)文件里面定義模板,并在模板的定義和(非定義的)聲明的前面加上關(guān)鍵字export。
還是以上面的代碼為例:
(1) MyClass.h
#include
#include
// 類模板聲明
export template
class MyClass{
public:
// 聲明
T getT();
void setT(T t);
private:
T t;
}; (2) MyClass.cpp
#include "MyClass.h"
export template
T MyClass::getT() {
return t;
}
export template
void MyClass::setT(T t) {
this->t = t;
} 以上代碼能否編譯通過(guò)取決于你的編譯器,大部分是無(wú)法編譯通過(guò)的,這代碼和包含模式對(duì)比起來(lái)是不是有一種脫褲子放屁的感覺(jué)?
看起來(lái)關(guān)鍵字export的分離模式更加符合C++源碼組織習(xí)慣,為什么這種寫(xiě)法再C++的模板沒(méi)有流行起來(lái)呢? 這是因?yàn)樵贑++標(biāo)準(zhǔn)推出幾年之后,也就只有極少的公司真正提供了對(duì)export關(guān)鍵字的支持。于是,export這個(gè)特性未能像其他C++特性那樣廣為流傳, 這就使得程序員在很多編譯器下都不能正常使用export的分離模式。
當(dāng)前標(biāo)題:理解C++之類模板
分享URL:http://m.fisionsoft.com.cn/article/dphdggg.html


咨詢
建站咨詢
