模板初阶详解


感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

泛型编程

下面是实现各种类型的交换函数

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, typename T2,......,typename Tn>这里的T1..代表类型

用函数模板实现交换功能如下

template<typename T>
void Swap( T& left, T& right)
{
 T temp = left;
 left = right;
 right = temp;
}

在这里插入图片描述
T代表所有的类型,所以也可以交换char类型的变量
在这里插入图片描述

注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

函数模板的原理

上面的模板中不同类型的变量都调用了Swap,现在有一个问题就是Swap(a,b)和Swap(c,d)是否用的同一个Swap函数

事实上他们调用的并不是同一个Swap函数,因为a b的类型和c d的类型是不一样的,也就是函数模版中的T是未知类型,根据传入参数类型生成一个匹配的函数

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

隐式实例化

让编译器根据实参推演模板参数的实际类型

在上面已经演示过一个例子了
在这里插入图片描述
但是如果我们传入的参数不符合模板规定就会报错
在这里插入图片描述
这里的Swap模板中的T只能表示一种类型,而我们传入的参数中包含了int类型和double类型,也就是说T的类型即是int也是double,显然这是不可能的,所以出现参数T不明确这个错误

解决方案有三种,第一种是强制类型转换,第二种就是显示实例化,第三种就是用多个不同的T(T1 T2 T3…)

强制类型转换的疑惑

但是关于强制类型转换这里我有一点疑惑

void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 1, b = 2;
	double c = 1.001, d = 2.001;
	Swap(a, b);
	Swap((int)c, a);
	cout << a << "\n" << b << endl;
	cout << c << "\n" << d << endl;
	return 0;
}

在这里插入图片描述
按理来说强制类型转换后参数类型就相同了,并且就算double类型和int类型数据进行交换,也应该只是出现数据丢失这种情况,但是不会报错,而这里却出现了问题,所以我不是很清楚

而再看看下面这个例子,在没有强制类型转换前是报错的,而强制类型转换后可以正常运行
在这里插入图片描述
在这里插入图片描述

显式实例化

在函数名后的<>中指定模板参数的实际类型

template<typename T1>
T1 ADD(const T1& left, const T1 right)
{
	return left + right;
}
int main()
{
	int a = 1;
	double b = 2.001;
	cout << ADD<int>(a, b) << endl;
	cout << ADD<double>(a, b) << endl;
	return 0;
}

在这里插入图片描述
Swap函数还是会报错,但是后面我发现了一句话:如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错,可能是因为这个才报错的
在这里插入图片描述
但是第三中方法是可以解决这个问题的

template<typename T1,typename T2>
T1 ADD(const T1& left, const T2 right)
{
	return left + right;
}
int main()
{
	int a = 1;
	double b = 2.001;
	cout << ADD(a, b) << endl;
	return 0;
}

这里会出现数据丢失,所以输出的结果是3
在这里插入图片描述
再来看看Swap会不会报错

template<typename T,typename T1>
void Swap(T& left, T1& right)
{
	T temp = left;
	left = right;
	right = temp;
}

int main()
{
	int a = 1, b = 2;
	double c = 1.001, d = 2.001;
	Swap(a, b);
	Swap(c, a);
	cout << a << "\n" << b << endl;
	cout << c << "\n" << d << endl;
	return 0;
}

c之所以等于2是因为c在交换前,a和b已经交换了,所以c在和a交换的时候其实是1.001和2交换
而a之所以等于1,是因为在c和a交换后,a为1.001,然后因为a是int类型导致数据丢失
在这里插入图片描述

模板参数的匹配原则

template<typename T>
T ADD(const T& left, const T& right)
{
	return left + right;
}
int ADD(const int& left, const int& right)
{
	return left + right;
}
int main()
{
	int a = 1, b = 2;
	cout << ADD(a, b) << endl;
	return 0;
}

这段代码可以正常运行,但是现在又一个问题就是两个ADD函数,一个是通用模板,另一个是现成的函数,到底是用的哪一个呢?
在这里插入图片描述

显然为偷懒,当然是用现成的函数,所以我们调用的函数是先从的ADD函数

而下面这种就不是调用现成的ADD函数了,因为这里用了显示实例化,也就表示了你必须调用模板函数,让T变成int类型,即使有现成的函数也不可以偷懒

在这里插入图片描述

类模板

类模板的定义格式

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

类模板的实例化

来看看下面的例子

template<typename T>
class A
{
public:
	T ADD(const T& left, const T& right)
	{
		return left + right;
	}
private:
	T a;
	int b;
};
int main()
{
	int c = 0, d = 2;
	double e = 0.0001, f = 1.0001;
	A <int>a;
	A<double>b;
	cout << a.ADD(c, d) << endl;
	cout << b.ADD(e, f) << endl;
	return 0;
}

类模版的实例化都是显示实例化,也就是在定义的时候我们就要规定T是什么类型,例如A < int> a表示这a这个对象中T是int类型,其次类中的函数也是和之前的模板函数一样的
在这里插入图片描述

相关推荐

  1. 【C++】模板

    2024-07-13 09:58:04       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-13 09:58:04       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-13 09:58:04       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-13 09:58:04       62 阅读
  4. Python语言-面向对象

    2024-07-13 09:58:04       72 阅读

热门阅读

  1. 开源项目有哪些机遇与挑战?

    2024-07-13 09:58:04       24 阅读
  2. Spring Boot集成Atomix快速入门Demo

    2024-07-13 09:58:04       25 阅读
  3. Python实现网站IP地址查询

    2024-07-13 09:58:04       23 阅读
  4. parquet-go的CSVWriter

    2024-07-13 09:58:04       30 阅读
  5. 玩转鸿蒙NXET之组件导航与路由跳转二

    2024-07-13 09:58:04       25 阅读
  6. Go语言入门之数组切片

    2024-07-13 09:58:04       31 阅读
  7. P6. 对局列表和排行榜功能

    2024-07-13 09:58:04       24 阅读
  8. 使用Nginx实现高效负载均衡

    2024-07-13 09:58:04       23 阅读
  9. CRC32简述

    2024-07-13 09:58:04       27 阅读
  10. 赛博灯泡3.0,未完善,无bug

    2024-07-13 09:58:04       23 阅读
  11. C#——二进制流序列化和反序列化

    2024-07-13 09:58:04       31 阅读