C++模板的注意事项
函數模板
template <typename T> //把typename換成class也可以函數模板調用方法
使用過程中, 有兩種方法調用, 如下:
- 自動類型推導:
- 顯示指定類型
注意, 兩者的區別在于調用時是否傳入模板類型.
函數模板調用規則
- 普通函數調用時可以發生隱式類型轉換
- 函數模板, 用自動類型推導, 不能發生隱式類型轉換
- 函數模板, 用顯示指定類型, 可以發生隱式類型轉換?
普通函數和函數模板調用順序規則
假設有以下例子:
#include <iostream> using namespace std;void mSwap(int &first, int &second) {cout << "call normal function" << endl;int temp;temp = first;first = second;second = temp; }template <class T> void mSwap(T &first, T &second) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp; }- 如果函數模板和普通函數都可以調用, 優先調用普通函數
示例代碼:
int main() {int a = 10;int b = 20;mSwap(a, b);return 0; }結果:
?
- 可以通過空模板參數列表強制調用函數模板
示例:
int main() {int a = 10;int b = 20;mSwap<>(a, b);return 0; }結果:
- 函數模板可以發生函數重載
比如又加了一個函數:
template <class T> void mSwap(T &first, T &second) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp; }template <class T> void mSwap(T &first, T &second, T &third) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp; }現在就有兩個同名函數模板了, 這樣傳入三個參數就會調用下面的.?
- 如果函數模板可以產生更好的匹配(不需要發生隱式類型轉換), 優先調用函數模板
比如有如下調用:
int main() {char a = 'a';char b = 'b';mSwap(a, b);return 0; }運行結果為:
函數模板局限性
比如有如下代碼:
class People { public:People(string name, int age) : m_name(name), m_age(age) {}string m_name;int m_age; };template <class T> bool mCompare(const T &a, const T &b) {if (a == b)return true;elsereturn false; }?當有如下調用時:
int main() {People p1("michael", 18);People p2("michael", 18);mCompare(p1, p2);return 0; }會發生如下編譯錯誤:
出現以上情況我們當然可以在類中實現" == "的運算符重載, 也可以用如下的方法, 在以上代碼的基礎上增加以下代碼:
template<> bool mCompare(const People &a, const People &b) {if (a.m_name == b.m_name &&a.m_age == b.m_age)return true;elsereturn false; }這樣即對以上的函數模板進行people定制化重載。
類模板
在類的聲明按照如下聲明:
template <class nameType, class ageType> class People { public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age; };這樣使用的時候按照如下使用:
int main() {People<string, int> p1("michael", 18);return 0; }類模板中成員函數創建時機
類模板中成員函數在調用時才創建.
如下測試代碼:
class People1 { public:void showPerple1(){cout << "this is class People1" << endl;} };class People2 { public:void showPerple2(){cout << "this is class People2" << endl;} };template <class T> class mClass { public:void show1() {m_obj.showPerple1();}void show2() {m_obj.showPerple2();}T m_obj; };如上代碼是可以編譯通過的.
如下測試代碼:
int main() {mClass <People1> p1;mClass <People2> p2;p1.show1();p2.show2();return 0; }?編譯時候確定了T的類型之后, 如果發現T中沒有成員函數中的函數, 就會報錯.
類模板的對象作函數參數
假設有如下模板類:
template <class nameType, class ageType> class People { public:People(const nameType &name, const ageType &age) : m_name(name), m_age(age) {}void show() {cout << "name: " << m_name << endl;cout << "age: " << m_age << endl;}nameType m_name;ageType m_age; };如果想要調用People實例化對象的show函數, 可以有以下方法:
- 指定傳入類型
方法如下:
void showPeople1(People<string, int> &p) {p.show(); }int main() {People<string, int> p1("michael", 18);showPeople1(p1);return 0; }- 參數模板化
方法如下:
template <class nameType, class ageType> void showPeople2(People<nameType, ageType> &p) {p.show(); }int main() {People<string, int> p2("michael", 18);showPeople1(p2);return 0; }- 整個類模板化
方法如下:
template <class P> void showPeople3(P &p) {p.show(); }int main() {People<string, int> p3("michael", 18);showPeople3(p3);return 0; }類模板繼承
- 當父類是模板類時, 子類在繼承的時候需要指定父類中的模板類型, 當有如下代碼:
這樣編譯會報錯, 需要改為:
template <class T> class Father { public:T m_T; };class Son : public Father<int> { public: };這樣就可以了?
- 也可以把子類也變成模板類, 可以按照如下操作:
類外實現
當有如下類:
template <class nameType, class ageType> class People { public:People(nameType name, ageType age);void showPeople();nameType m_name;ageType m_age; };當我們在類外實現其構造函數和成員函數時, 需要按照如下方式:
//constructor template <class nameType, class ageType> People<nameType, ageType>::People(nameType name, ageType age) {m_name = name;m_age = age; }//member function template <class nameType, class ageType> void People<nameType, ageType>::showPeople() {cout << "name: " << m_name << endl;cout << "age: " << m_age << endl; }類模板的分文件編寫
類模板與友元
函數模板和類模板的區別
- 類模板是不存在類型推導的, 所以實例化對象的時候必須傳入類型.
- 類模板是可以有默認參數的
可參考如下代碼:
template <class nameType, class ageType = int> class People { public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age; };int main() {People<string> p1("michael", 18);return 0; }這樣是可以的.
如果兩個參數都有默認類型, 實例化對象的時候也必須要有尖括號, 如下:?
template <class nameType = string, class ageType = int> class People { public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age; };int main() {People <>p1("michael", 18);return 0; }模板的特化
模板的設計是為了有效減少代碼量,但是某些情況,對于某種特定類型,模板就需要進行特化。
全特化和偏特化
全特化就是限定死模板實現的具體類型,偏特化就是如果這個模板有多個類型,那么只限定其中的一部分。
函數模板的特化
函數模板只能進行全特化不能進行偏特化,函數模板的全特化可以參照上文說的,正常函數就是相當于對函數模板的全特化。
類模板的特化
template<typename T1, typename T2> class Test { public:Test(T1 i,T2 j):a(i),b(j){cout<<"模板類"<<endl;} private:T1 a;T2 b; };template<> class Test<int , char> { public:Test(int i, char j):a(i),b(j){cout<<"全特化"<<endl;} private:int a;char b; };template <typename T2> class Test<char, T2> { public:Test(char i, T2 j):a(i),b(j){cout<<"偏特化"<<endl;} private:char a;T2 b; };那么下面3句依次調用類模板、全特化與偏特化:
Test<double , double> t1(0.1,0.2); Test<int , char> t2(1,'A'); Test<char, bool> t3('A',true); //依次打印: //類模板 //全特化 //偏特化總結
以上是生活随笔為你收集整理的C++模板的注意事项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode45 --- jump
- 下一篇: c语言乘法表只有结果,要求输出结果显示相