目錄
- 泛型編程
- 函數模板
- 函數模板概念
- 函數模板格式
- 函數模板的原理
- 函數模板的實例化
- 隱式實例化
- 強制類型轉換的疑惑
- 顯式實例化
- 模板參數的匹配原則
- 類模板
- 類模板的定義格式
- 類模板的實例化
感謝各位大佬對我的支持,如果我的文章對你有用,歡迎點擊以下鏈接
🐒🐒🐒 個人主頁
🥸🥸🥸 C語言
🐿?🐿?🐿? C語言例題
🐣🐣🐣 python
🐓🐓🐓 數據結構C語言
🐔🐔🐔 C++
🐿?🐿?🐿? 文章鏈接目錄
泛型編程
下面是實現各種類型的交換函數
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
上面函數功能完全相同,只是傳入的參數類型不同,如果我們在要一一實現的話就太麻煩了,所以如果有一個公用的模板,可以支持不同類型的傳參就好了
函數模板
函數模板概念
函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定類型版本
函數模板格式
template<typename T1, typename T2,......,typename Tn>這里的T1..代表類型
用函數模板實現交換功能如下
template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}
T代表所有的類型,所以也可以交換char類型的變量
注意:typename是用來定義模板參數關鍵字,也可以使用class(切記:不能使用struct代替class)
函數模板的原理
上面的模板中不同類型的變量都調用了Swap,現在有一個問題就是Swap(a,b)和Swap(c,d)是否用的同一個Swap函數
事實上他們調用的并不是同一個Swap函數,因為a b的類型和c d的類型是不一樣的,也就是函數模版中的T是未知類型,根據傳入參數類型生成一個匹配的函數
函數模板的實例化
用不同類型的參數使用函數模板時,稱為函數模板的實例化。模板參數實例化分為:隱式實例化和顯式實例化。
隱式實例化
讓編譯器根據實參推演模板參數的實際類型
在上面已經演示過一個例子了
但是如果我們傳入的參數不符合模板規定就會報錯
這里的Swap模板中的T只能表示一種類型,而我們傳入的參數中包含了int類型和double類型,也就是說T的類型即是int也是double,顯然這是不可能的,所以出現參數T不明確這個錯誤
解決方案有三種,第一種是強制類型轉換,第二種就是顯示實例化,第三種就是用多個不同的T(T1 T2 T3…)
強制類型轉換的疑惑
但是關于強制類型轉換這里我有一點疑惑
void Swap(T& left, T& right)
{T temp = left;left = right;right = temp;
}
int main()
{int a = 1, b = 2;double c = 1.001, d = 2.001;Swap(a, b);Swap((int)c, a);cout << a << "\n" << b << endl;cout << c << "\n" << d << endl;return 0;
}
按理來說強制類型轉換后參數類型就相同了,并且就算double類型和int類型數據進行交換,也應該只是出現數據丟失這種情況,但是不會報錯,而這里卻出現了問題,所以我不是很清楚
而再看看下面這個例子,在沒有強制類型轉換前是報錯的,而強制類型轉換后可以正常運行
顯式實例化
在函數名后的<>中指定模板參數的實際類型
template<typename T1>
T1 ADD(const T1& left, const T1 right)
{return left + right;
}
int main()
{int a = 1;double b = 2.001;cout << ADD<int>(a, b) << endl;cout << ADD<double>(a, b) << endl;return 0;
}
Swap函數還是會報錯,但是后面我發現了一句話:如果類型不匹配,編譯器會嘗試進行隱式類型轉換,如果無法轉換成功編譯器將會報錯,可能是因為這個才報錯的
但是第三中方法是可以解決這個問題的
template<typename T1,typename T2>
T1 ADD(const T1& left, const T2 right)
{return left + right;
}
int main()
{int a = 1;double b = 2.001;cout << ADD(a, b) << endl;return 0;
}
這里會出現數據丟失,所以輸出的結果是3
再來看看Swap會不會報錯
template<typename T,typename T1>
void Swap(T& left, T1& right)
{T temp = left;left = right;right = temp;
}int main()
{int a = 1, b = 2;double c = 1.001, d = 2.001;Swap(a, b);Swap(c, a);cout << a << "\n" << b << endl;cout << c << "\n" << d << endl;return 0;
}
c之所以等于2是因為c在交換前,a和b已經交換了,所以c在和a交換的時候其實是1.001和2交換
而a之所以等于1,是因為在c和a交換后,a為1.001,然后因為a是int類型導致數據丟失
模板參數的匹配原則
template<typename T>
T ADD(const T& left, const T& right)
{return left + right;
}
int ADD(const int& left, const int& right)
{return left + right;
}
int main()
{int a = 1, b = 2;cout << ADD(a, b) << endl;return 0;
}
這段代碼可以正常運行,但是現在又一個問題就是兩個ADD函數,一個是通用模板,另一個是現成的函數,到底是用的哪一個呢?
顯然為偷懶,當然是用現成的函數,所以我們調用的函數是先從的ADD函數
而下面這種就不是調用現成的ADD函數了,因為這里用了顯示實例化,也就表示了你必須調用模板函數,讓T變成int類型,即使有現成的函數也不可以偷懶
類模板
類模板的定義格式
template<class T1, class T2, ..., class Tn>
class 類模板名
{// 類內成員定義
};
類模板的實例化
來看看下面的例子
template<typename T>
class A
{
public:T ADD(const T& left, const T& right){return left + right;}
private:T a;int b;
};
int main()
{int c = 0, d = 2;double e = 0.0001, f = 1.0001;A <int>a;A<double>b;cout << a.ADD(c, d) << endl;cout << b.ADD(e, f) << endl;return 0;
}
類模版的實例化都是顯示實例化,也就是在定義的時候我們就要規定T是什么類型,例如A < int> a表示這a這個對象中T是int類型,其次類中的函數也是和之前的模板函數一樣的