類模板學(xué)習(xí)參考書籍:王健偉《C++新經(jīng)典:模板與泛型編程》
創(chuàng)新互聯(lián)網(wǎng)站建設(shè)服務(wù)商,為中小企業(yè)提供成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計服務(wù),網(wǎng)站設(shè)計,網(wǎng)站托管維護等一站式綜合服務(wù)型公司,專業(yè)打造企業(yè)形象網(wǎng)站,讓您在眾多競爭對手中脫穎而出創(chuàng)新互聯(lián)。
和函數(shù)模板一樣,類模板可以理解為產(chǎn)生類的模具,通過給定的模板參數(shù)生成具體的類。vector容器就是一個類模板應(yīng)用的例子,vector可以存放不同類型的數(shù)據(jù)類型元素,其就是通過引入類模板來減少不同類型元素存儲時重復(fù)的代碼,代碼更加精簡和通用。示例如下:
#includeusing namespace std;
template//標(biāo)識符為T的模板參數(shù),表示myvector容器所保存的元素類型
class myvector
{public:
typedef T* myiterator; // 迭代器
public:
myvector(); //構(gòu)造函數(shù)
myvector(T tmpt) // 帶參數(shù)的構(gòu)造函數(shù)
{
}
myvector& operator=(const myvector&); // 重載賦值運算符,在類模板中使用模板名可以不用提供模板參數(shù),如myvectorpublic:
void myfunc()
{cout<< "mufunc() 被調(diào)用"<< endl;
}
public:
// 迭代器接口
myiterator mybegin(); //迭代器起始位置
myiterator myend(); //迭代器結(jié)束位置
};
templatemyvector::myvector() // 類外構(gòu)造函數(shù)實現(xiàn)
{}
int main()
{myvectortempvec; //T被替換成int,即指定模板參數(shù)T為int
myvector tempvec1(6); // 不用指定模板參數(shù)
tempvec.myfunc(); //調(diào)用類模板中的普通成員函數(shù)
}
對于類模板myvector,myvector稱為類名或類模板,myvectormyvector& operator=(const myvector&);
,但在類模板外不可以,如myvector
。
對于類模板的模板參數(shù)推導(dǎo),代碼myvector tempvec1(6);
中,我們通過調(diào)用含參數(shù)的構(gòu)造函數(shù)實例化模板類,編譯器通過傳入的實參類型可以自動推導(dǎo)出T的類型。而myvector
則是通過類名<類型>
指定T的類型(倘若沒有帶參數(shù)的構(gòu)造函數(shù),T仍需指定)。實現(xiàn)模板參數(shù)推導(dǎo)的功能是通過使用推斷指南(deduction guide),其作用為推斷類模板參數(shù)時提供推斷指引。一般我們常見的(如上面代碼中的例子)都為隱式推斷指南,無需指定(前提是待傳入?yún)?shù)的構(gòu)造函數(shù)存在)編譯器自動推斷。當(dāng)然,程序員也可以自定義推斷指南(如不存在構(gòu)造函數(shù)的情況)。形式如下:
templateA(T,T)->A;
對于類模板的特化。類模板的全特化如下:
template<>class myvector{public:
myvector()
{cout<< "全特化版本"<< endl;
}
void myfunc();
};
void myvector::myfunc()
{cout<< "全特化版本的myfunc"<< endl;
}
int main()
{myvectortempvec;
tempvec.myfunc();
}
需要區(qū)分的是,泛化版本的類模板和全特化版本的類模板只是同名,兩者實例化后的對象是完全不同的兩個類,即成員屬性和函數(shù)無法共享。其次對在全特化版本類模板外定義的成員函數(shù)不能在開頭加template<>
,相當(dāng)于全特化后變成了一個普通類。
普通成員函數(shù)和靜態(tài)變量的全特化如下:
#includeusing namespace std;
template//標(biāo)識符為T的模板參數(shù),表示myvector容器所保存的元素類型
class myvector
{public:
typedef T* myiterator; // 迭代器
static int m_stc; // 靜態(tài)變量聲明
public:
myvector(); //構(gòu)造函數(shù)
myvector(T tmpt) // 帶參數(shù)的構(gòu)造函數(shù)
{}
myvector& operator=(const myvector&); // 重載賦值運算符,在類模板中使用模板名可以不用提供模板參數(shù),如myvectorpublic:
void myfunc();
public:
// 迭代器接口
myiterator mybegin(); //迭代器起始位置
myiterator myend(); //迭代器結(jié)束位置
};
templatemyvector::myvector() // 類外構(gòu)造函數(shù)實現(xiàn)
{cout<< "泛化版本的構(gòu)造函數(shù)被調(diào)用"<< endl;
}
template<>class myvector{public:
myvector()
{cout<< "全特化版本"<< endl;
}
void myfunc();
};
void myvector::myfunc()
{cout<< "全特化版本的myfunc"<< endl;
}
templatevoid myvector::myfunc()
{cout<< "泛化版本的普通成員函數(shù)myfunc()被調(diào)用"<< endl;
}
template<>void myvector::myfunc()
{cout<< "泛化版本的普通成員函數(shù)myfunc()的全特化版本被調(diào)用"<< endl;
}
templateint myvector::m_stc = 10;
template<>int myvector::m_stc = 100;
int main()
{myvectortempvec;
tempvec.myfunc();
cout<< tempvec.m_stc<< endl;
}
在上述代碼的mian函數(shù)中,我們使用myvector
指令模板參數(shù)類型為float實例化了類模板,因為myvector類模板存在全特化版本,所以編譯器會先找到全特化版本,但是由于全特化版本中模板參數(shù)特化類型為int,class myvector
,所以只能使用泛化版本,因此運行的是泛化版本的構(gòu)造函數(shù)。接著,運行代碼tempvec.myfunc();
,tempvec是泛化版本示例化后的類,所以myfunc
函數(shù)也是泛化版本中的,不過在泛化版本中存在全特化的同名函數(shù),所以會優(yōu)先選擇其。不過由于該成員函數(shù)的全特化版本模板參數(shù)類型為double,void myvector
,不是該實例化類中模板參數(shù)float,所以該全特化函數(shù)不會取代原來的同名成員函數(shù)。對于模板類中的靜態(tài)變量m_stc同理。亦然,我們?nèi)绻铋_始指定模板類型為double,那么會依次執(zhí)行泛化版本的構(gòu)造函數(shù),泛化版本的全特化myfunc成員函數(shù),輸出泛化版本的m_stc靜態(tài)變量。想一想,如果實例化類的模板參數(shù)類型為int,那么cout<< tempvec.m_stc<< endl;
必然會報錯,因為類模板的全特化版本中沒有這一靜態(tài)變量。
注意:如果進行了普通成員函數(shù)或靜態(tài)成員變量的全特化,那么就無法用這些全特化時指定的類型對整個類模板進行全特化了。因為在對成員函數(shù)或靜態(tài)成員變量進行了全特化后導(dǎo)致實例化了對應(yīng)類型的類模板,如果再次進行全特化,將不會重復(fù)進行相同類型的實例化,編譯器報錯。
對于類模板的偏特化有兩種:一是模板參數(shù)數(shù)量上的偏特化;一是模板參數(shù)范圍上的偏特化。具體實現(xiàn)和原理類似于函數(shù)模板的偏特化。
對于默認(rèn)參數(shù):
myvector<>tmpvec
。template
。類型別名,可以通過typedef或者using關(guān)鍵字給類型名起一個別名。
typedef TCIF_TC;
using IF_TCU = TC;
和函數(shù)模板一樣,類模板中同樣也可以有非類型模板參數(shù),但全局指針、浮點數(shù)和字符串常量不能作為非類型模板參數(shù)。
成員函數(shù)模板示例如下:
#includeusing namespace std;
templateclass A
{public:
A(double v1, double v2) // 普通構(gòu)造函數(shù)
{cout<< "A::A(double,double)執(zhí)行了!"<< endl;
}
A(T1 v1, T1 v2) // 使用類模板參數(shù)類型的構(gòu)造函數(shù)
{cout<< "A::A(T1,T1)執(zhí)行了!"<< endl;
}
templateA(T2 v1, T2 v2); // 構(gòu)造函數(shù)模板
templatevoid myfunc(T3 tmpt) // 普通成員函模板
{cout<< tmpt<< endl;
}
T1 m_ic;
static constexpr int m_stcvalue = 200;
};
// 在類外實現(xiàn)類模板的構(gòu)造函數(shù)模板
template// 先寫類模板的模板參數(shù)列表
template// 再寫構(gòu)造函數(shù)模板自己的模板參數(shù)列表
A::A(T2 v1, T2 v3)
{cout<< "A::A(T2,T2)執(zhí)行了!"<< endl;
}
int main()
{Aa(1, 2);
a.myfunc(3);
}
拷貝構(gòu)造函數(shù)模板不等同且永遠(yuǎn)不可能成為拷貝構(gòu)造函數(shù),拷貝賦值運算符模板不等同且永遠(yuǎn)不可能成為拷貝賦值運算符。類型相同的對象拷貝構(gòu)造調(diào)用的是拷貝構(gòu)造函數(shù),類型不同的對象拷貝構(gòu)造調(diào)用的是拷貝構(gòu)造函數(shù)模板,并不會因為找不到對應(yīng)調(diào)用對象而且調(diào)用另一個。
對于成員函數(shù)模板也具有特化版本。
類模板嵌套相關(guān)資料表示,C++標(biāo)準(zhǔn)不允許在類模板之外全特化一個未被全特化的類模板的成員函數(shù)模板。即在類模板外,如果要全特化一個成員函數(shù)模板,需要確保該成員函數(shù)模板所屬的類模板為全特化版本。
類模板中套類模板和類中類相差不大。需要注意的是,將子類模板的成員函數(shù)寫在父類模板的泛化版本之外,應(yīng)當(dāng)如下形式:
template//父類模板參數(shù)列表
template//子類模板參數(shù)列表
void A::B::myfunc()
{}
變量模板與成員變量模板變量模板定義和使用如下:
#includeusing namespace std;
templateT myvar{}; // 變量模板,{}為零初始化
int main()
{myvar= 13;
myvar= 13.1;
cout<< myvar<< " "<< myvar<< endl;
}
不同的指定類型得到不同的變量。
templateT myvar{}; // 泛化版本
template<>char myvar{}; // 全特化版本,myvar可以當(dāng)作char類型使用
templateT myvar{120}; // 偏特化版本
templateT myvar{}; // 默認(rèn)模板參數(shù)
templateT myvar[val]; // 非類型模板參數(shù)
templateclass A
{public:
templatestatic W m_tpi; // 成員變量模板
};
// 成員變量模板在類模板外定義
templatetemplateW A::m_tpi = 5;
別名模板與成員別名模板別名模板的作用主要是簡化書寫。
#include
模板模板參數(shù)之前我們學(xué)習(xí)的模板參數(shù)有類型模板參數(shù)和非類型模板參數(shù),這一部分將提出模板模板參數(shù),即模板參數(shù)本身為模板,將類模板當(dāng)作參數(shù)傳遞到另一個模板中。我們在學(xué)習(xí)類模板的時候知道vector、list等容器類其實也是類模板,所以若我們想要將這些容器類作為模板參數(shù)傳入模板中,寫法如下:
#include#include#includeusing namespace std;
templateclass Container = std::vector>//templatetypename Container = std::vector>class myclass
{public:
Containermyc;
public:
void func();
myclass()
{for (int i = 0; i< 10; i++)
{ myc.push_back(i); // 本行代碼正確性取決于模板參數(shù)類型
}
}
};
templateclass Container>void myclass::func()
{cout<< "mstifiy"<< endl;
}
int main()
{myclassmylistobj; // double是容器中的元素類型,list是容器類型
mylistobj.func();
std::cout<< mylistobj.myc.size()<< endl;
}
其中重點注意模板參數(shù)列表的寫法:
templateclass Container = std::vector>templatetypename Container = std::vector>// class也能替換成typename修飾
templatetypename Container = std::vector>// W為容器模板的類型模板參數(shù),不能用,故省略
templatetypename Container>// 沒有默認(rèn)模板參數(shù)
class和typename可以相互替代,都是合法的。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
本文名稱:【C++泛型學(xué)習(xí)筆記】類模板、變量模板和別名模板-創(chuàng)新互聯(lián)
本文網(wǎng)址:http://jinyejixie.com/article46/isceg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、用戶體驗、企業(yè)建站、定制開發(fā)、品牌網(wǎng)站制作、網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容