C++浅谈模板
·
C++浅谈模板
1、 泛型编程
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;
}
这是几个交换函数的重载,每个函数的逻辑相似,只有传参的类型不同。写一份几乎相同的函数,冗余而且很难维护
能不能写出一种通用函数,能够接收不同类型的参数呢?
- 在C++中用泛型编程解决了这个问题
- 泛型编程用于编写与类型无关的通用代码,同时保证了类型安全,实现一份代码适配多种类型
- C++主要通过模板实现泛型编程,包括函数模板和类模板
2、 函数模板
函数模板是一种“通用函数”,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
语法://声明类型 参数T,typename可以换成class(不可以换成struct)
//template <typename T1, typename T2>
//返回值类型 函数名(参数列表){函数模板实现}
下面是用函数模板写的交换函数
#include<iostream>
using namespace std;
/T是类型参数,表示任意类型
template<typename T>
void Swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 1, y = 2;
/自动推导出T=int,生成Swap<int>示例
Swap(x, y);
cout << x << " " << y << endl;
double a = 1.1, b = 2.2;
/自动推导出T=double,生成Swap<double>示例
Swap(a, b);
cout << a << " " << b << endl;
string s1 = "haha", s2 = "hehe";
/自动推导出T=string,生成Swap<string>示例
Swap(s1, s2);
cout << s1 << " " << s2 << endl;
return 0;
}
函数模板原理
函数模板是一种“蓝图”,定义时不指定具体类型,用类型参数(typename T)代替。编译器通过传入的实参自动推导类型,并实现模板实例化。
简单来说,模板时编译器自动生成了很多份函数重载

3、 函数模板实例化
1)隐式实例化, 编译器根据函数调用的实参自动推导类型参数,并生成对应实例
2) 显式实例化, 在函数名后的<>中指定模板参数的实际类型
4、 模板函数的匹配原则
- 如果函数模板与普通函数重载同时存在,编译器遵循优先级:精确匹配的普通函数>显式指定类型的模板函数>模板函数的隐式实例化>隐式类型转后的普通函数(模板函数不允许自动类型转换,但普通函数可以进行自动类型转换)
- 强调:模板函数不允许自动类型转换,必须严格匹配推导的类型(或显式指定类型)
// 普通函数
void f(int a) {
cout << "普通函数\n";
}
// 函数模板
template<class T>
void f(T a) {
cout << "模板函数\n";
}
int main() {
f(10); // 1. 精确匹配普通函数 → 调用普通函数
f<int>(10); // 2. 显式指定模板 → 调用模板
f('a'); // 3. 普通函数需要char转int,模板精确匹配 → 调用模板
f(3.14); // 4. 普通函数不匹配,模板匹配 → 调用模板
}
//普通函数(支持自动类型转换)
// 普通函数
void func(int a)
{
cout << "普通 int 函数" << endl;
}
int main()
{
func(10); // 精确匹配
func('a'); // char 自动转 int (允许)
func(3.14); // double 自动转 int (允许)
}
//模板函数(不允许自动类型转换)
template<class T>
void add(T a, T b)
{
}
int main()
{
add(10, 20); // T=int
add(1.5, 2.5); // T=double
add(10, 2.5); // 报错!
// 编译器:
// 第一个参数是 int → T=int
// 第二个参数是 double → T=double
// 类型冲突!
// 模板绝不帮你把 int 转 double
}
5、 类模板
语法
类模板的实例化
使用类模板时,需显式指定类型参数(编译器无法像函数模板那样自动推导类的类型参数),将实例化的类型放入<>,类模板名字不是真正的类,实例化的结果才是真正的类
#include<iostream>
using namespace std;
/类模板:通用栈
template<class T>
class Stack
{
public:
Stack(int capacity = 4)
:_data(new T[capacity])
,_top(-1)
,_capacity(capacity)
{}
~Stack()
{
delete[]_data;
}
void push(const T& val)
{
...
}
private:
T* _data;
int _top;
int _capacity;
};
int main()
{
/实例化int类型的栈
/Stack 是类名,Stack<int>才是类型
//Stack s; //错误!类模板不能自动推导
Stack<int> s;
/实例化string类型的栈
Stack<string> t;
}
注意区分类函数和类模板
为什么类模板不能自动推导?
因为类是在定义对象时确定类型,不像函数有参数可以用来推导。
// 没有参数给编译器看,编译器怎么知道 T 是什么?MyStack s;
更多推荐


所有评论(0)