🌟個人主頁:第七序章??
🌈專欄系列:C++
目錄
??前言:
🌈1.泛型編程:
🌈2.函數模板
🍭2.1函數模板概念
🍭2.2函數模板格式
🍭2.3 函數模板的原理
🍭2.4 函數模板的實例化
🍭2.5 函數模版的匹配原則
🌈3. 類模板
🍭3.1 類模板的定義格式
🍭3.2 類模板的實例化
🌈4.關鍵問題
🍉問題 1:
🍉問題 2:
🍉問題 3:
🌻共勉:
??前言:
上一篇我們學習了C/C++的內存管理,今天我們來學習一下C++的函數模板和類模板。
🌈1.泛型編程:
泛型編程?: 編寫與類型無關的通用代碼,是代碼復用的一種手段。模板是泛型編程的基礎? ? ??
🥝template 模版關鍵字
template< class T>
template< typename T>
🥝模版參數傳遞的是類型;函數參數傳遞的是對象值。
🥝模版的定義和聲明不支持分別在兩個文件里面【會出現鏈接錯誤,所有的鏈接錯誤都是符號表找不到】因為編譯器的模版T是無法確定的,無法生成符號表。
🥝模版是不支持聲明與定義分別放到.h和.cpp中,一般都是需要放到一個文件中。有些地方就會命名成.hpp【頭文件和定義實現內容合并到一起】但是并不是必須是.hpp,.h也是可以的。
🌈2.函數模板
🍭2.1函數模板概念
🥝函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定類型版本。
🍭2.2函數模板格式
🥝template<typename T1, typename T2,…,typename Tn> 返回值類型 函數名(參數列表){}
template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}
🥝注意: typename是用來定義模板參數關鍵字,也可以使用class(切記:不能使用struct代替class)
🍭2.3 函數模板的原理
?
🥝在編譯器編譯階段,對于模板函數的使用,編譯器需要根據傳入的實參類型來推演生成對應類型的函數以供 調用。
🥝比如:當用double類型使用函數模板時,編譯器通過對實參類型的推演,將T確定為double類型,然后產生一份專門處理double類型的代碼, 對于字符類型也是如此
🍭2.4 函數模板的實例化
- 隱式實例化:讓編譯器根據實參推演模板參數的實際類型
- 顯式實例化:在函數名后的<>中指定模板參數的實際類型
int main(void)
{int a = 10;double b = 20.0;// 顯式實例化 Add<int>(a, b); return 0;
}
🍭2.5 函數模版的匹配原則
🥝1.一個非模板函數【專門的函數】可以和一個同名的函數模板同時存在,而且該函數模板還可以被實例化為這個非模板函數。
🥝2.對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模板。
🥝3.模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換
🌈3. 類模板
🍭3.1 類模板的定義格式
template<class T1, class T2, ..., class Tn>
class 類模板名
{// 類內成員定義
};
template<class T>
class Stack
{
public:Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;cout << "Stack(size_t capacity = 4)" << endl;}~Stack(){delete[] _array;_capacity = 0;_size = 0;}void push(const T& data);
private:T* _array;int _capacity;int _size;
};//聲明和定義分離的寫法 不建議分離到.h 和.cpp
template<class T>
void Stack<T>::push(const T& data)
{_array[_size++] = data;
}
🍭3.2 類模板的實例化
🥝類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字后跟<>,然后將實例化的類型放在<> 中即可。類模板名字不是真正的類,而實例化的結果才是真正的類
// Vector類名,Vector<int>才是類型 Vector<int> s1;Vector<double> s2;
int main()
{Stack<int> st1; // 實例化為處理int類型的Stack類,st1是該類對象Stack<double> st2; // 實例化為處理double類型的Stack類,st2是該類對象return 0;
}
說明:
Stack
是類模板名,Stack<int>
、Stack<double>
才是具體的類類型。
🌈4.關鍵問題
🍉問題 1:
函數模板的隱式實例化和顯式實例化有何區別?在什么情況下需要使用顯式實例化?
?答案:區別主要體現在模板參數確定方式和類型轉換處理上。隱式實例化由編譯器根據實參自動推演模板參數的實際類型,且編譯器一般不進行類型轉換;顯式實例化需在函數名后
<>
中手動指定模板參數類型,類型不匹配時編譯器會嘗試隱式類型轉換。當出現隱式實例化無法確定模板參數的情況(如 Add (int, double),模板僅一個參數 T),或需要明確指定模板參數類型以滿足特定需求時,需使用顯式實例化
🍉問題 2:
類模板與函數模板在實例化方面有哪些核心差異?
?答案:一是實例化觸發方式,函數模板可通過隱式(編譯器推演)或顯式(手動指定)實例化,類模板只能通過顯式實例化(需在類模板名后
<>
指定類型);二是名稱性質,函數模板實例化時,模板名可通過實參推演關聯具體類型,而類模板名本身不是真正的類,只有實例化后的結果(如 Stack<int>)才是具體的類類型
🍉問題 3:
當非模板函數與同名函數模板同時存在時,編譯器的調用匹配規則是什么?
?答案:有三條核心規則。第一,非模板函數與同名函數模板可共存,模板還能實例化為該非模板函數;第二,其他條件相同時,優先調用非模板函數,若模板能生成參數更匹配的函數版本(如非模板函數處理 int,模板可處理 int 與 double 組合),則選擇模板;第三,模板函數不允許自動類型轉換,而普通函數可以,這也會影響調用匹配結果(如實參類型不匹配時,普通函數可能通過自動轉換匹配,模板函數則報錯)
🌻共勉:
以上就是本篇博客的所有內容,如果你覺得這篇博客對你有幫助的話,可以點贊收藏關注支持一波~~🥝
?