【C++学习】模板初阶-----提供极大的便利

在写这篇文章的时候,我想到了一个很有趣的事情。
csdn,也提供了一些模板。
在这里插入图片描述
实际上,日常生活中我们经常会用到模板。
就比如我,在某团买团购后,都习惯给商家好评,然后就会参照某个模板来写,改变了商家的名字和一些商品而已。模板给了我们很大的便利,不用重复多次的写差不多的东西。而C++中,也提供了模板。

C++中的模板有两种:函数模板、类模板

函数模板

假设想编写一个函数对两个数进行相加,考虑到相加的类型可能会不同,第一次我可能会尝试利用重载定义多个函数。

//两个int类型相加
int Add(int x1, int x2)
{
	return (x1 + x2);
}
//两个float类型相加
double Add(double x3, double x4)
{
	return (x3 + x4);
}

int main(void)
{
	int a = 11;
	int b = 22;
	double c = 3.14;
	double d = 1.42;
	
	int ret_int = Add(a, b);
	int ret_double = Add(c, d);

	return 0;
}

它们实现的都是相加的意图,虽然C++支持重载,但是仅仅只由于类型不同就要再写一份,这样的方法未免太笨拙了!可不可以提供一份模板,让编译器根据情况自己生成呢?答案是可以的。

【函数模板的含义】

函数模板代表了一个函数家族,它与类型独立(即与类型无关),在使用的时候被参数化,根据调用时的实参按照模板定义出特定的类型版本。

函数模板的格式为
template<typename T1, typename T2, ……,typename Tn>

template<class T1, class T2, ……, class Tn>

这里要注意的点:

  • 后面没有分号
  • <>里面为参数列表,使用逗号分隔
  • 模板形参列表不能为空
//格式1:template<typename T1, typename T2, ……,typename Tn>
template<typename T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
//格式2:template<class T1, class T2, ……,class Tn>
template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

编译器会根据提供实参,按照模板定义出一份特定的函数。

函数模板是一个蓝图,它本身并不是函数,是编译器定义特定具体类型函数的模具。所以模板就是将应该我们做的重复的事情交给了编译器。

在这里插入图片描述
有一个有趣的点:如果写了一份模板,并且已经有了一份现成的,编译器会报错吗?如果正确,编译器会做何选择?

template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
int main(void)
{
	int i1 = 11;
	int i2 = 22;
	Swap(i1, i2);
	return 0;
}

答案是,编译器并不会报错,它会使用现成的,而不是根据模板再定义出一份。
你可以想象:如果你是一个铁匠,此时此刻你需要一个扳手,你的身边恰好有一个合适的扳手和一个制作扳手的模具。你会选择用现成的,还是用模具造出一个扳手再拿来使用?毋庸置疑,选择现成的扳手才是此时此刻最佳的选择!

模板的实例化

在使用函数模板的时候,编译器会根据实际的模板实参,使用实参替代相应的模板形参产生编译该版本的函数,这就是模板的实例化。
模板参数实例化分为:隐式实例化和显示实例化

【隐式实例化】
隐式实例化,就是在实例化的过程中,让编译器根据实参自己推演模板参数的实际类型。

但是有时候却是一个问题,看看下面这段代码:
在这里插入图片描述

编译器会出现报错,这是因为“没有与参数列表匹配的 函数模板 “Add” 实例”,而且模板函数不允许自动类型转换。
这个情况下有两种解决方案:

  • 一、在调用时强制类型转化
    在这里插入图片描述
  • 二、显示实例化

【显示实例化】
显式实例化,就是在实例化的过程中,显示地指定模板参数的类型,具体操作为在函数名后增加"<>"。“<>”里为指定的模板参数的实际类型
在这里插入图片描述
相较于强制类型转化,显示实例化更加地理想。

inline函数模板

函数模板也可以被inline修饰,声明为inline。
它的修饰方式与普通函数略为不同。

修饰方式:template <typename T> inline

//可被inline修饰,但是inline要放在模板参数列表之后,返回类型之前
template <class T> inline
T Add(const T& x, const T& y)
{
	return x + y;
}

int main(void)
{
	int a = 11;
	double c = 3.14;
	Add<int>(a, c);
	return 0;
}

类模板

我假定你已经学习了函数模板……

同定义函数模板一样,也可以定义出类模板。
类模板定义的格式

//类模板定义格式
template <typename T1, typename T2, ……,typename Tn>
class 类模板名
{
    //……
};

为了更好地说明类模板,我将参照标准程序库中的stack类,实现一个简单的版本my_stack类,my_stack这个类将支持不同类型的对象,意味着我们需要使用到类模板。

//类模板例子
template <typename T>
class my_stack
{
public:
	my_stack()
		:_arry(nullptr)
		,_top(0)
		,_capacity(0)
	{
		;
	}
	void push_my_satck(T push_val)
	{
		//定义
	}
	void pop_my_stack()
	{
		//定义
	}
	//返回栈顶元素
	T top_my_stack()
	{
		//定义
	}
	//……
	~my_stack()
	{
		free(_arry);
		_arry = nullptr;
		_top = _capactiy = 0;
	}
private:
	T* _arry;
	int _top;
	int _capacity;
};

这段程序中,我将类模板中的函数在类体内进行了定义。
而如果在类体外定义需要注意:类模板中的成员函数放在类体外定义时,需要加模板参数列表。

//如果在类体外定义push_my_stcak成员函数
//需要加模板参数列表
template <typename T>
void my_stack<T>::push_my_stack(T val)
{
 //语句
}

类模板的实例化

和函数模板的实例化有些不同,类模板在创建对象的时候必须显示指定实参,才能实例化,类模板的名字不是真正的类,实例化的结果才是真正的类

//例如
my_stack<int> s1;
my_stack<char> s2;
my_stack<double> s3;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小酥诶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值