C++模板基础

1. 泛型编程

编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础,解决代码冗余。

问题场景:实现通用交换函数时,需为不同类型重复编写逻辑相同的代码:

cpp 复制代码
void Swap(int& a, int& b) { /*...*/ }  
void Swap(double& a, double& b) { /*...*/ }  
void Swap(char& a, char& b) { /*...*/ }  

传统缺陷

  • 代码复用率低:新增类型需手动添加函数
  • 可维护性差:一处出错,所有重载均受影响

解决方案模板------编译器根据类型自动生成代码的"模具"。

2. 函数模板

  • 模板函数代表了一个函数家族,该函数模板与类型无关,在使用时根据实参类型产生特定的函数版本。

2.1 基本语法

cpp 复制代码
template<typename T>  // typename 或 class
//返回值类型 函数名(参数列表){}
T Swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

2.2 底层原理

  • 编译器根据传入的实参类型来推演生成对应类型的函数,以供调用。例如,根据实参类型推演,将T确定为double类型,然后产生一份专门处理double类型的代码。
cpp 复制代码
double d1,d2;
Swap(d1, d2);  // 生成 double Swap(double&, double&)
int i1,i2
Swap(i1, i2);  // 生成 int Swap(int&, int&)

如同"工业模具",填入不同材料(类型),产出不同铸件(具体函数)

2.3 实例化方式

  • 隐式实例化:编译器根据实参自动推演类型
  • 显式实例化:手动指定类型,不需要推演
cpp 复制代码
template<class T>//也可以用template<typename T>
T Add(const T& left, const T& right)
{
	cout << "T Add(const T& left, const T& right)" << endl;
	return left + right;
}

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.2, d2 = 20.1;
	//模板会根据参数推演实际的类型,生成对应类型的函数.
    Add(a1, a2);//T->int
	Add(d1, d2);//T->double
	
    //模板参数列表只有一个T,编译器无法确定将T确定为int或者double而报错
    //Add(a1, d1);
	//解决方式1:强转
	Add(a1, (int)d1);//将d1强制转换成int型,或将a1强制转换成double型
	//解决方式2:显式实例化,在函数名后的<>中指定模板参数的实际类型
	Add<double>(a1, d1);//指定为double型
}

2.4 匹配优先级规则

  • 优先匹配普通函数:非模板函数可以和一个同名的函数模板同时存在。在运行中,参数类型与非模板函数完全匹配,则不需要函数模板实例化,会优先调用非模板函数,如果不想使用非模板函数,可以显式实例化,调用模板函数。
cpp 复制代码
template<class T>//也可以用template<typename T>
T Add(const T& left, const T& right)
{
	cout << "T Add(const T& left, const T& right)" << endl;
	return left + right;
}

int Add(int& left, int& right)
{
	cout << "int Add(int& left, int& right)" << endl;
	return left + right;
}
int main()
{
	//非模板函数和一个同名的函数模板可同时存在,而且该函数模板可以被实例化为这个非模板函数
	int a1 = 10, a2 = 20;
	Add(a1, a2);//与非函数模板完全匹配,不需要函数模板实例化,直接调用非模板函数
	Add<int>(a1, a2);//将模板函数显式实例化为int Add(int& left, int& right)这个非模板函数
}
  • 模板生成更优匹配时,选择模板:如果模板可以产生一个更好的匹配函数,优先选则模板
cpp 复制代码
int Add(int left, int right)
{
	cout << "int Add(int& left, int& right)" << endl;
	return left + right;
}
template<class T1, class T2>
auto Add(T1 left, T2 right)
{
	cout << "auto Add(T1 left, T2 right)" << endl;
	return left + right;
}
void Test()
{
	Add(1, 2);//与非函数模板类型完全匹配,不需要函数模板实例化
	//如果不存在模板函数,这个会被强制类型转换成int型,匹配int Add
	//如果存在模板函数,且模板函数可以生成更匹配的版本,编译器根据实参生成更匹配的auto Add函数
	Add(1, 2.8);
}

3. 类模板

通用数据结构的设计利器

格式

cpp 复制代码
template<class T1, class T2, ... , class Tn>
class 类模板名
{
    //类内成员定义
};

模板不建议定义和声明分离到.h和.cpp,会出现链接错误。eg:

cpp 复制代码
template<class T>
class Vector
{
private:
	T* _pData;//指针,指向T类型的空间
	size_t _size;
	size_t _capacity;
public:
	Vector(size_t capacity = 10)
		:_pData(new T[capacity])//new T[capacity],连续开辟10个T类型的空间。_pData(new T[capacity]),连续开辟10个T类型的空间,_pData指向开辟空间的首元素位置
		,_size(0)
		,_capacity(capacity)
	{}
	~Vector();//类中声明,类外定义
	void PushBack(const T& data);
	void PopBack();

	size_t Size()
	{
		return _size;
	}

	T& operator[](size_t pos)
	{
		assert(pos < _size);
		return _pData[pos];
	}
};

//类外定义时必须携带模板头 template<class T>

template <class T1>
Vector<T1>::~Vector()
{
	if (_pData)
		delete[] _pData;
	_size = _capacity = 0;
}
template <class T2>
void Vector<T2>::PushBack(const T2& data)
{
	T2[_size] = data;
	_size++;
}
template <class T3>
void Vector<T3>::PopBack()
{
	_size--;
}

int main()
{
	//类模板实例化,一个模板实例化不同类型
	Vector<int> s1;//类似把T替换成int,存储int类型的类
	Vector<double> s2;//类似把T替换成double,存储double类型的类
}

函数模板可以通过实参推演,类模板只有显式实例化,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,实例化的结果才是真正化的类。

在上述程序中,Vector 是模板,Vector<int> 才是真实类型。

4. 模板核心优势总结

场景 传统方式 模板解决方案
通用函数 重载多个函数 单个函数模板覆盖所有类型
通用数据结构 为不同类型重复实现相同逻辑 类模板一次定义多类型复用
避免隐式类型转换 普通函数自动转换可能丢失精度 显式实例化严格类型控制
相关推荐
编程爱好者熊浪8 分钟前
RedisBloom使用
java
苇柠20 分钟前
Spring框架基础(1)
java·后端·spring
yics.24 分钟前
数据结构——栈和队列
java·数据结构
架构师沉默30 分钟前
我用一个 Postgres 实现一整套后端架构!
java·spring boot·程序人生·架构·tdd
xiucai_cs34 分钟前
布隆过滤器原理与Spring Boot实战
java·spring boot·后端·布隆过滤器
向阳花自开36 分钟前
Spring Boot 常用注解速查表
java·spring boot·后端
huan_19931 小时前
通过docker构建一个java镜像
java·docker
岁忧1 小时前
(LeetCode 面试经典 150 题) 82. 删除排序链表中的重复元素 II (链表)
java·c++·leetcode·链表·面试·go
胖咕噜的稞达鸭2 小时前
单链表专题---暴力算法美学(1)(有视频演示)
算法
秋难降2 小时前
【数据结构与算法】———回溯之美
数据结构·算法