C++5:初见模板
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
虽然学习了类和对象能很方便的处理一些容器类的问题但是我们还是会遇到如下这种情况。
我们创建一个简单的stack类
class Stack
{
public:
Stack()
{}
private:
int* _a;
size_t _top;
size_t _capacity;
};
我们单独处理int类型需要使用栈结构的时候还好说假如我们需要使用double或者其他类型的变量时操作会变得很难受复制一段改数据类型吗?代码变得膨大不说还难以管理诚然我们可以使用typedef来方便修改可是每一次运行都要更改还是挺蛋疼的。
所以为了应对一些函数仅仅只是传参数据类型不同但是逻辑相同而需要重载函数的情况C++给出了模板。
template <typename T>
void Swap(T& x,T& y)
{
T tmp = x;
x = y;
y = tmp;
}
用起来嘎嘎顺手嘎嘎好用。
如上所记述的是函数模板我们还有类模板我们一个个来看
函数模板
template <typename T1typename T2>
void Swap(T& x,T& y)
{
T tmp = x;
x = y;
y = tmp;
}
注意:typename是用来定义模板参数关键字也可以使用class(切记:不能使用struct代替class)
上文所展示的函数模板其实是类似于蓝图的样式本身需要我们自己思考编写对应类型的这个过程被模板参数所取代这个过程取而代之变成了编译器的工作也就是推导的过程成了编译器的事情我们可以在这方面偷懒了。
编译器推到的大致过程如下:
当用double类型使用函数模板时编译器通过对实参类型的推演将T确定为double类型然
后产生一份专门处理double类型的代码int也是同理。
模板的这种工作原理很像用模具做冰棍不是吗?同一个模具生产出不同口味的冰棍
函数模板的实例化:
实例化有两种方式:显示实例化隐式实例化
隐式实例化
我们上文所述的方法就是隐式实例化通过对函数模板传递参数来让编译器自己推演得到对应的参数类型并生成对应类型的函数。
但其实我们不能去依赖编译器的推演能力因为它本身的推演能力不太行具体体现如下文:
虽然说我们上文的交换函数是完全没啥问题的但是如果换成两个不同的类型让编译器去尝试推导就不行了。比如我们的Swap函数我们分别传一个int和double进去
因为我们本身的模板参数只有一个T传过来第一个T编译器推导为int而第二个是个double就把编译器干懵了那这个T到底是int还是double?
解决办法:
1.多加一个模板参数
template <typename T1,typename T2> void Swap(T1& x, T2& y) { T1 tmp = x; x = y; y = tmp; }
2.使用者自己强制类型转换
当然对于Swap函数来讲这个也是不起作用的所以为了举例换成Add函数
当然还有其他的办法来弥补编译器推演能力不足的问题显式实例化就是其中之一。
显示实例化
显示实例化的本质就是不再让编译器推演我们直接指定传入的变量类型具体操作是在函数名后的<>中指定模板参数的实际类型
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add<int>(a1, d1);
}
我们可以看到编译器直接将两个模板参数变量都变成了int类型但其实在这个过程中还是发生了隐式类型转换。
类模板
上文我们把模板参数套在了函数头上我们也可以套到类形成类模板。
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
以STL举例STL各种容器指定存放数据类型的基本实现就是依仗于模板的比如Vector
int main()
{
vector<int> v1;
}
我们在类模板名后传入指定需要的变量类型编译器就会生成对应类型的类。
学习了基本的模板就可以去玩一玩STL了。