文章目錄
C++編程提高——模板
一、模板的概念
模板就是建立通用的模具,打打提高複用性
模板的特點:
- 模板不可以直接使用,它只是一個框架
- 模板的通用並不是萬能的
二、函數模板
- C++另一種編程思想稱爲泛型編程,主要利用的技術就是模板
- C++提供兩種模板機制:函數模板和類模板
2.1函數模板語法
函數模板的作用:
建立一個通用函數,其函數返回值類型和形參類型可以不具體指定,用一個虛擬的類型來代表
語法:
template<typename T>
函數聲明或定義
解釋:
template
:聲明創建模板
typename
:表面其後面的符號是一種數據類型,可以用class代替
T
:通用的數據類型,名稱可以替換,通常爲大寫字母
示例:
template<typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
void test11() {
int a = 10;
int b = 20;
//自動類型推導
//mySwap(a, b);
//設置類型
mySwap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
2.2函數模板注意事項
注意事項:
- 自動類型推導,必須推導出一致的數據類型T,纔可以使用
- 模板必須要確定出T的數據類型,纔可以使用
2.3普通函數與函數模板的區別
- 普通函數調用時可以發生自動類型轉換(隱式類型轉換)
- 函數模板調用時,如果利用自動類型推導,不會發生隱式類型轉換
- 如果利用顯示指定類型的方式,可以發生隱式類型轉換
2.4普通函數與函數模板的調用規則
如下:
- 如果函數模板和普通函數都可以實現,優先調用普通函數
- 可以通過空模板參數列表來強制調用函數模板
- 函數模板也可以發生重載
- 如果函數模板可以產生更好的匹配,優先調用函數模板
三、類模板
3.1類模板語法
作用:建立一個通用類,類中的成員數據類型可以不具體制定,用一個虛擬的類型代表。
語法:
template<typename T>
類
解釋:
template
:聲明創建模板typename
:表面其後面的符號是一種數據類型,可以用class代替T
:通用的數據類型,名稱可以替換,通常爲大寫字母
示例:
#include<iostream>
using namespace std;
template<class nameType, class ageType>
class Person {
public:
Person(nameType name, ageType age) {
this->name = name;
this->age = age;
}
void showInfo() {
cout << "name = " << this->name << endl;
cout << "age = " << this->age << endl;
}
nameType name;
ageType age;
};
int main() {
Person<string, int> p1("張三", 20);
p1.showInfo();
/*
name = 張三
age = 20
*/
system("pause");
return 0;
}
3.2類模板與函數模板的區別
- 類模板沒有自動推導的使用方式
- 類模板在模板參數列表中可以有默認參數
template<class nameType, class ageType = int>
3.3類模板中成員函數創建時機
- 普通類中的成員函數在一開始就可以創建
- 類模板中的成員函數在調用時才創建
3.4類模板對象做函數參數
一共有三種傳入方式:
- 指定傳入的類型:直接顯示對象的數據類型
- 參數模板化:將對象中的參數變爲模板進行傳遞
- 整個類模板化:將這個對象類型模板化進行傳遞
示例:
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
void showInfo() {
cout << "name = " << this->name << endl;
cout << "age = " << this->age << endl;
}
T1 name;
T2 age;
};
//使用直接指定類型
void testT31(Person<string, int> p) {
p.showInfo();
}
void test31() {
Person<string, int> p("Tom", 20);
testT31(p);
}
//將參數模板化
template<class T1, class T2>
void testT32(Person<T1, T2> p) {
p.showInfo();
}
void test32() {
Person<string, int> p("Jack", 18);
testT32(p);
}
//將整個類模板化
template<class T>
void testT33(T p) {
p.showInfo();
}
void test33() {
Person<string, int> p("Rose", 30);
testT33(p);
}
int main() {
test31();
test32();
test33();
/*
name = Tom
age = 20
name = Jack
age = 18
name = Rose
age = 30
*/
system("pause");
return 0;
}
3.5類模板與繼承
注意:
- 當子類繼承的父類是一個模板類時,子類在聲明時要指定出父類中T的類型
- 如果不指定,編譯器無法給子類分配內存
- 如果想靈活的指定出父類中T的類型,子類也需要變爲類模板
3.6成員函數類外實現
示例:
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showInfo();
T1 name;
T2 age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showInfo() {
cout << "name = " << this->name << endl;
cout << "age = " << this->age << endl;
}
3.7類模板分文件編寫
問題:
- 類模板中成員函數創建時機是在調用階段,導致分文件編寫時鏈接不到
解決:
- 直接包含
.cpp
文件 - 將聲明和實現寫到同一個文件中,並後綴名改爲
.hpp
,此名稱爲約定的名稱,並不是強制
3.8類模板與友元
全局函數類內實現:直接在類內聲明友元即可
全局函數類外實現:需要提前讓編譯器知道全局函數的存在
示例:
#include<iostream>
using namespace std;
//需要讓編譯器知道Person的存在
template<class T1, class T2>
class Person;
//類外實現友元
template<class T1, class T2>
void getPersonMsg2(Person<T1, T2> p) {
cout << "name = " << p.name << " age = " << p.age << endl;
}
template<class T1, class T2>
class Person {
//類內實現友元
friend void getPersonMsg(Person<T1, T2> p) {
cout << "name = " << p.name << " age = " << p.age << endl;
}
//類外實現需要添加空模板參數列表
friend void getPersonMsg2<>(Person<T1, T2> p);
public:
Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
private:
T1 name;
T2 age;
};
int main() {
Person<string, int> p("tom", 20);
getPersonMsg(p);
getPersonMsg2(p);
system("pause");
return 0;
}