【C++】模板 templateⅠ:原理、使用细节、函数模板、类模板


🔗自用链接…请忽略


1. 重载,不能解决的问题

从 C 语言刚学 C++ 重载的时候,只有一个想法:重载好阿,重载妙啊,想用重载大展拳脚。

🌰一个残酷对比奉上:

// 是从 C 开始就被我们写烂的 Swap 函数

/******************************  重载  ****************************/
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)
{
	double tmp = left;
	left = right;
	right = tmp;
}

/******************************  模板  ****************************/
template<class T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

(在你盘算重载参数有没有写齐全的同时,模板已经写出三份了~

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

为解决这个问题,我们引入 泛型编程 的概念,

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

模板分为 函数模板类模板


2. 模板的原理

在这里插入图片描述
在这里插入图片描述

如图所示,使用函数模板看似只写了一个函数,实际上该有的重载函数一个不少,只是不再需要用户去反复编写,而是通过模板实例化自动生成。

⭕注意:

  1. 模板的声明或定义只能在 全局命名空间类范围内 进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

  2. 如果定义和声名分开写,两份都需要声明 template

  3. 类模板的定义和声明尽量放在一个文件下,可以分开方式但会很麻烦。(具体方式见下篇)

  4. 类模板的名称:类名 <参数>


3. 函数模板

函数模板,定义时,简化了函数参数,使其与具体类型无关,在使用时,根据实参类型被实例化,产生函数的特定类型版本以供使用。

写法:

template<class T1, class T2>			// T 为自定义名,class 也可写作 typedef
函数...

🌰举个例子:

  1. 👣 定义模板:
template<class T>
T Add(T a, T b)
{
	return a + b;
}
  1. 👣 使用模板
使用模板函数有两种方式:
☝️隐式实例化,传参过程中,自动推演模板类型,
实参前面可加强制类型转化。
✌️显式实例化,直接声明参数类型,不需要推演,
传参的过程中,参数会视情况进行隐式类型转换。
/***********************  测试及结果如下  ***********************/
void testAdd()
{
	int a1 = 10, a2 = 20;
	double d1 = 1.88, d2 = 2.77;

	// 隐式实例化
	cout << Add(a1, a2) << endl;					// 30
	cout << Add(d1, d2) << endl;					// 4.65
	cout << Add(a1, (int)d1) << endl;				// 11
	cout << Add((double)a1, d1) << endl;			// 11.88
	//cout << Add(a1, d1) << endl;		// 报错,因为类型与模板不一致,这里可以回忆一下 auto 的使用规则
	
	// 显式实例化
	cout << Add<int>(a1, d1) << endl;				// 11
	cout << Add<double>(a1, d1) << endl;			// 11.88
}
-----------
测试结果:
30
4.65
11
11.88
11
11.88
  1. 👣 函数模板 与 函数 同时存在

如果用户定义了相应参数类型的函数,会调用用户定义的!!一是用户可以 个性化定制,二是 执行效率更高,不需要模板实例化。

ps:如果在有用户定义的情况下,还想用模板,可以用模板显式实例化。

// 将下面这个函数放入上面的代码段,仍然调用 testAdd() 进行测试
int Add(int a, int b)	
{
	cout << "int Add() = ";
	return a + b;
}

/***********************  测试及结果如下  ***********************/
int Add = 30
4.65
int Add = 11
11.88
11
11.88

4. 类模板

函数模板 解决了 函数重载 的限制问题,类模板 将解决 typedef 的限制问题,针对仅数据成员和成员函数类型不同的类。

🤔问:typedef 差在哪儿啦?

typedef int STDataType;
class Stack
{
		//...	
private:
	STDataType* _a;
	size_t _top;
	size_t _capacity;
};

/**** 要求,创建两个对象,其中成员_a的类型分别为 int* 和 double* ****/
int main()
{
	Stack st1;	// int
	Stack st2;	// ...还是int
	
	return 0;
}

//(typedef 内心 os:写完 main 函数是我最后的倔强

答:无法创建多类型的对象成员!!

🌰类模板的写法和函数模板异曲同工,直接上代码:

template<class T>
class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = new T[capacity];	// try catch 暂时不考虑
		_top = 0;
		_capacity = 0;
	}
	~Stack();		// 类中声明,类外定义

private:
	T* _a;
	size_t _top;
	size_t _capacity;
};


template<class T>	// 需要再次 template
Stack<T>::~Stack()	// 类模板类型名称:类名<参数>
{
	delete[] _a;	// 方括号!!!!匹配使用,一定注意检查
	_top = 0;
	_capacity = 0;
}

int main()
{
	Stack<int> st1;
	Stack<double> st1;

	return 0;
}
	这是一段 不学模板 看不懂的代码:

	vector<int> v;										// 模板、类对象

	for(int i = 0; i < v.size(); ++i)
	{
		cout << v[i] << " ";							// 运算符重载
	}
	

5. 模板 Ⅰ 总结

  1. <class / typedef T> 两种写法都可取,T 是自定义名称 通常大写,多个参数时,用逗号间隔。

  2. 使用模板函数时可以将 参数类型 显式实例化

  3. 函数模板和同名函数可以同时存在,优先调用用户定义的 同名函数
    (有同名函数时,可以显式实例化模板)

  4. 模板的 声明或定义 只能在 全局、命名空间、类 范围内进行。即不能在局部范围,函数内进行,比如不能在 main 函数中声明或定义一个模板。

  5. 如果定义和声名分开写,声明 也需要标记 template

  6. 模板的 定义声明 尽量写在 一个文件中,可以分开方式但会很麻烦。(具体方式见下篇)

  7. 类模板的名称:类名 <参数>

  8. 多多使用为益!!


接下篇 🔗进阶,特殊情况的处理🔗

👉【C++】模板 template Ⅱ:模板的非类型模板参数、模板特化(函数模板、类模板)、为什么模板不支持分离编译


文末,私心放一些正儿八经的优质文,都是本篇提及到的相关内容,欢迎点赞收藏~🥰

🔗函数重载、auto
🔗运算符重载
🔗内存管理函数 new / delete


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值