C++学习之路-Template模板

什么是泛型

了解模板之前,先了解一个概念:泛型。

泛型,实质上就是不使用具体数据类型(例如 int、double、float等),而是使用一种通用类型来进行程序设计的方法,该方法可以大规模的减少程序代码的编写量,让程序员可以集中精力用于业务逻辑的实现。是一种将类型参数化进而达到代码复用的技术,强调的是,在C++中是使用模板来实现泛型。

通过需求,引出模板的作用

通常使用普通的函数实现一个与数据类型有关的算法是很繁琐的,比如两个数的加法,要考虑很多类型:

int add(int a, int b)
{
	return a + b;
}

double add(double a, double b)
{
	return a + b;
}

Point add(Point a, Point b) 
{
	return a + b; //这里面的加号是被运算符重载过的
}

在C++中可以通过函数重载来解决这个问题,但是反复写相同算法的函数是比较辛苦的,更重要的是函数重载是静态编译,运行时占用过多内存。在此我们可以用C++的模板函数来表达通用型的函数,如下:

template <typename T>  // 模板声明
T add(T a, T b)  // 类型参数化,T就是占位符,等待传入的参数是(int、double、Point)
{
	return a + b;
}

其中:template < typename T> 是模板的声明,下面的T add(T a, T b) 就是模板函数了,T为待传入的类型参数,比如(int double Point)。这样的话,编译器会根据传入参数的类型,自动实现不同类型的函数运算,非常的高效便捷。

其中 typename 完全可以换成class,这两个是完全等价的

template <class T>
T add(T a, T b)
{
	return a + b;
}

模板定义的规则

占位符T仅仅是一个符号

typename 后跟的“T”只是一个占位符而已,是自定义的,可以改成任意字符,只需要全部统一即可。但是,尽量统一,不要乱写符号,尽量写成T,因为T可以认为是Type的简称。

template <class ZMM>
ZMM add(ZMM a, ZMM b)
{
	return a + b;
}

总之,我们这样定义,代表ZMM这种类型是可以发生变化的,可以接受任意类型参数,进而完成类似于函数重载的工作。

那么,代码中的 T 是什么呢?很明显,这是一个占位符,更确切的说是一个类型占位符。也就是说,将来在 T这个位置上的是一个真实、具体的数据类型,至于到底是哪个类型,完全取决于用户的需求。

当然,如果硬要给 T 这种类型占位符也叫做一种数据类型,提供这种想法的发明者称它为泛型(generic type),而使用这种类型占位符的编程方式就被称为泛型编程。

然后,我们在调用add函数时,就可以传入不同的类型,调用不同的函数:这里,调用函数并打印返回值

cout << add(1, 2) << endl;
cout << add(1.1, 2.2) << endl;
cout << add(Point(1,2), Point(2, 3)) << endl;

但,其实,完整的调用是这样的:

cout << add<int>(1, 2) << endl;
cout << add<double>(1.1, 2.2) << endl;
cout << add<Point>(Point(1,2), Point(2, 3)) << endl;

编译器很智能,根据传入参数自动判断类型是什么,所以才有了省略的写法。

我们如果想要程序更加正规,就采取完整的写法,比较清晰。知道完整调用之后,我想我们可以理解类型参数化是什么意思了,也就是将int/double/Point传递给参数T,然后生成一个新的函数。

多类型参数的模板写法

假如,我想要传进去的参数,一个是int类型,一个是double类型,返回的是float类型,如何实现呢?

template <typename T1, typename T2, typename T3> // 多类型参数
T3 add(T1 a, T2 b) // 不同类型修饰不同变量,要与自己需求对应准确
{
	return a + b;
}

调用时:这种返回值类型和参数类型不同的情况,必须完整调用,即要在函数名后面完整的写清楚<类型参数>

add<int,double,float>(1, 2.12);//完整调用,明确参数都是什么

泛型的原理本质

我们通过传入不同的参数,达到了不同类型之间的计算问题。即,C++通过模板实现了泛型。那么泛型的原理是什么呢?

根据不同的参数类型,调用相同的模板函数?但我根据函数重载的原理,我大概猜测应该是编译器通过模板函数生成了三个不同的函数,让我们通过汇编看看情况是不是这样

在这里插入图片描述

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

可以看出,传入不同类型参数时,编译器会根据模板为其生成一个全新函数,供其调用。也就是在调用函数时,模板会立马生成一个。但是如果不调用函数,编译器就不会生成函数,因为都不知道你传入的参数是啥,编译器也不知道生成什么类型的函数。

也就意味着:我只有调用函数了,模板才会触发,才会生成对应的函数。就像类一样,只有创建对象才有类的存在,否则编译器根本不care。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值