C++入门七式——模板初阶

发布于:2025-04-21 ⋅ 阅读:(64) ⋅ 点赞:(0)

目录

函数模板

函数模板概念

函数模板格式

函数模板的原理

函数模板的实例化

模板参数的匹配原则

类模板

类模板的定义格式

类模板的显式实例化 


当面对下面的代码时,大家会不会有一种无力的感觉?明明这些代码差不多,只是因为类型不同,就要多写几行代码。如果有泛型编程该有多好! 

void swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}
void swap(double& left, double& right)
{
	double tmp = left;
	left = right;
	right = tmp;
}
void swap(char& left, char& right)
{
	char tmp = left;
	left = right;
	right = tmp;
}

虽然在这种情况下,函数重载也可以实现,但是有以下几个不好的地方:

  1. 重载的函数仅仅是类型不同,代码复用效率比较低,只有当新类型出现时,就需要用户自己增加对应的函数。
  2. 代码的可维护性比较低,一个出错所有重载均出错。

那是否能告诉编译器一个模子,让编译器根据不同的类型利用该模子生成代码呢?这就要讲到我们今天的内容了——模板。

函数模板

函数模板概念

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

函数模板格式

#include<iostream>
using namespace std;
template <typename t>
//typename是用来定义模板参数关键字,也可以用class(不能用struct
void swap(t& x, t& y)
{
	t tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	return 0;
}

函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器使用方式产生了特定具体类型函数的模具。所以模板其实就是将本来该由我们做的重复的事情交给了编译器。

        编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数来调用 。

函数模板的实例化

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

1.隐式实例化:模板参数根据实参自动推演。

#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{
	return x + y;
}
int main()
{
	int a1 = 10, a2 = 22;
	double d1 = 10.23, d2 = 45.23;
	//隐式实例化
	add(a1, a2);
	add(d1, d2);
	//在模板中,编译器一般不会进行类型转换操作,因为一旦转化出现问题,编译器就需要背黑锅
	//add(a1, d1);
    //有两种解决方法:1.用户自己来强制转化2.使用显式实例化
    add(a1,(int)d1);
	return 0;
}

2. 显式实例化:在函数名后的<>中指定模板参数的实际类型

int main()
{
	int a1 = 10, a2 = 22;
	double d1 = 10.23, d2 = 45.23;
	//显式实例化
	add<int>(a1, a2);
	add<double>(d1, d2);
	add<int>(a1, d1);
	return 0;
}

模板参数的匹配原则

  • 一个非模板函数和一个同名函数模板可以同时存在 ,而且该函数模板还可以被实例化为这个非模板函数(现成的非模板函数优先)。

#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{
	cout << "模板" << endl;
	return x + y;
}
int add(int x, int y)
{
	cout << "现成" << endl;
	return x + y;
}
int main()
{
	int a1 = 10, a2 = 22;
	double d1 = 10.23, d2 = 45.23;
	add(a1, a2);
	return 0;
}

 

  • 对于非模板函数和一个同名函数,我们都可以调用,但会调用更匹配的。
#include<iostream>
using namespace std;
template<typename T1,typename T2>
T1 add(T1 x, T2 y)
{
	cout << "模板" << endl;
	return x + y;
}
int add(int x, int y)
{
	cout << "现成" << endl;
	return x + y;
}
int main()
{
	int a1 = 10, a2 = 22;
	double d1 = 10.23, d2 = 45.23;
	add(a1, d2);
	return 0;
}

 

 可以看出编译器会优先调用更匹配的模板,即使它比较麻烦。

类模板

基本都是显式实例化,因为无法借助数来推是什么类型

类模板的定义格式

template<class T1, class T2>
class t//类模板名
{

};

举例:

#include<iostream>
using namespace std;
template<class T>
class stack
{
public:
	stack(size_t capacity = 4)
	{
		_array = new T[capacity];
		_capacity = capacity;
		_size = 0;
	}
	void Push(const T& data);
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};
template<class T>
void stack<T>::Push(const T& data)
{
	_array[_size] = data;
	++_size;
}
int main()
{
	stack<int>st1;
	return 0;
}

类模板的显式实例化 

实例化模板需要在类模板后加<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

int main()
{
	stack<int>st1;
	return 0;
}