網站首頁 編程語言 正文
泛型編程在實際當中運用很廣泛,它可以不針對某種類型 (例如 int、double、float 等),能適應廣泛的類型,在很多需要重復編寫的代碼當中可以很大程度上減少程序的代碼量,提高效率
我們先思考一下,如何實現一個通用的交換函數呢?
//可以使用之前的函數重載的知識完成
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>//1個模板參數
template<typename T1, typename T2,......,typename Tn>//也可以多個
我們用函數模板再寫一下上面的交換函數
//用法
template<typename T>//在交換函數上面寫
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int a = 0, b = 1;
double c = 2.2, d = 3.2;
Swap(a, b);
Swap(c, d);
cout << a << " " << b << endl;//打印 1 0
cout << c << " " << d << endl;//打印 3.2 2.2
return 0;
}
函數模板大部分還會自動推導轉換的類型,這時我們只需寫一個交換函數,就可以實現多種類型的交換,很方便
函數模板的實例化
//用法
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);//隱式實例化 都是int 會自動推導int
Add(a1, d2);//這時兩個類型不同
Add<int>((a1, (int)d2);//顯示實例化 我們可以指定算的類型
return 0;
}
模板參數的匹配原則
我們看一個案例熟悉模板參數的匹配原則
案例:當模板函數和加法函數同時存在
//int的加法函數
int Add(int left, int right)
{
cout << "調用int加法函數" << endl;
return left + right;
}
//模板加法函數
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
cout << "調用模板加法函數" << endl;
return left + right;
}
void TestAdd1()
{
int ret=Add(1, 2);
cout << ret << endl;//類型都是int 此時會調用int加法函數
ret=Add(1, 2.0);
cout << ret << endl;//此時不全是int,會調用模板加法函數
ret=Add<int>(1, 2.0);
cout << ret << endl;//實例化后也會調用模板加法函數
}
int main()
{
TestAdd1();
}
對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而 不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模板
類模板的使用
先看一個我們完成棧的部分編程代碼,此時這個程序只是支持int類型的數據
//棧的實現
class Stack
{
public:
Stack(int capacity = 0)
{
_a = new int[capacity];
_capacity = capacity;
_top = 0;
}
~Stack()
{
delete[]_a;
_capacity = 0;
_top = 0;
}
void Push(int x)
{}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack st1;
st1.Push(1);
Stack st2;
st2.Push(2.2);
}
我們如果想插入double數據,在數據定義、申請內存、插入數據時都需要修改int,耽誤時間,這時我們就可以使用類模板
類模板使用格式:
template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內成員定義
};
我們在用類模板寫一下上面的棧實現
template<class T>
class Stack//類模板名
{
public:
Stack(int capacity = 0)
{
_a = new T[capacity];//new capacity個 T類型
_capacity = capacity;
_top = 0;
}
~Stack()
{
delete[]_a;
_capacity = 0;
_top = 0;
}
void Push(T x)
{}
private:
T* _a;
int _top;
int _capacity;
};
int main()
{
Stack<int> st1;//不能自動推導
st1.Push(1);//調用就可以傳是int的
Stack<double> st2;
st2.Push(2.2); //調用就是傳double的
}
使用類模板實現棧我們只需要在mian函數中將實例化的(double或int)類型放在<>中即可,省去我們去函數中一個個修改的時間
類模板的實例化
//類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字后跟<>,然后將實例化的
//類型放在<>中即可
Vector類名,Vector<int>才是類型
Vector<int> s1;
Vector<double> s2;
注意:類模板名字不是真正的類,而實例化的結果才是真正的類
模板的分離編譯
一個程序(項目)由若干個源文件共同實現,而每個源文件單獨編譯生成目標文件,最后將所有 目標文件鏈接起來形成單一的可執行文件的過程稱為分離編譯模式
注意事項:
當我們把上面加法模板函數聲明和定義分別放在.h和.cpp中時運行
// Add.h
template<class T>
T Add(const T& left, const T& right);
// Add.cpp
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
//main.cpp
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}
當我們把模板函數聲明和定義寫在兩個文件中,會出現以上鏈接錯誤報錯
解決方法:我們將聲明和定義放到一個文件 "xxx.hpp" 里面,就會運行正常
// Add.hpp
template<class T>
T Add(const T& left, const T& right);
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
//main.cpp
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}
所以,模板函數不支持聲明和定義寫在兩個文件中,會出現鏈接錯誤,如果要分離編譯的話,可以將聲明和定義都放在頭文件中,然后修改文件名后綴為.hpp
想了解更多分離編譯內容的話,可以去這個鏈接http://blog.csdn.net/pongba/article/details/19130
希望這篇文章大家有所收獲,我們下篇見
原文鏈接:https://blog.csdn.net/qq_72486849/article/details/125835436
相關推薦
- 2022-12-27 Python實現ATM簡單功能的示例詳解_python
- 2022-02-10 微信小程序this.triggerEvent(),父組件中使用子組件的事件
- 2023-07-24 前端終止請求的三種方式(ajax、axios)
- 2022-11-26 React?數據獲取與性能優化詳解_React
- 2022-08-02 使用Dockerfile實現容器內部服務隨容器自啟動的方法_docker
- 2024-01-11 spring 事務控制 設置手動回滾 TransactionAspectSupport.curren
- 2022-09-13 Nginx報錯104:Connection?reset?by?peer問題的解決及分析_nginx
- 2022-07-10 springboot 將logback日志根據不同類輸入到不同路徑下
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支