C++学习指南(三)——模板

欢迎来到繁星的CSDN。本期内容主要包括模板template。

目录

一、什么是模板?

      

二、函数模板

      模板的定义方式

      模板的实例化(确定参数的类型)

       隐式实例化

       显式实例化

       实例化顺序

三、类模板和模板类

      类模板的实例化


一、什么是模板?

        

    模板,工业生产上用以注塑吹塑挤出压铸锻压成型、冶炼冲压等方法得到所需产品的各种模子和工具。 简而言之,模板是用来制作成型物品的工具,这种工具由各种零件构成,不同的模板由不同的零件构成。它主要通过所成型材料物理状态的改变来实现物品外形的加工。素有“工业之母”的称号。

        不得不说,模板是工业上是堪比轮子的发明。

   而C++中,模板也正是我们“量产”代码,复用代码的关键。

template<class T>
void swap(T& a, T& b) {
	T tmp=a;
	a = b;
	b = tmp;
}

    如图,便是一个简单的swap函数,它支持任何两个同一类型的变量进行交换。

    (这里的swap改为大写的原因是,C++<iostream>库里有相同的swap函数,为了不影响演示,所以改了函数名字)

        但当我们输入的a和b类型不同的时候,系统会报错。

        这个问题先按下不表,等讲完函数模板,也就清晰了。

      

二、函数模板

        在刚刚的错误列表中,我们发现了函数模板字样。而事实上,模板分为函数模板和类模板。这一部分先叙述函数模板,因为函数模板往往是类模板的一个组成部分。

      模板的定义方式

        template的相关内容当然没有这么少。

template<class T1, class T2,.....>
(返回值类型)(函数名)(形参){
    //write code here
}

    模板关键字template可以同时定义多个虚拟类型的参数,T1,T2等等,程序员可以在这里写上百个参数,但在后面的模板里,你必须用到这些参数,否则编译器会报错。

        

    定义虚拟类型的关键字是typename或者class,这两种都可以且可以混用,但不能用struct!

     

    而对于同一个虚拟类型参数而言,编译器会在编译使其实例化的时候,让同一个虚拟参数全部编译为某一类型。

        所以,如果将代码按如下改造,便可以使得模板更灵活。

template<class T1,class T2>
void Swap(T1& a,T2& b){
    T1 tmp=a;
    a=b;
    b=tmp;
}

        因为T1和T2可以不为同一类型,也可以是同一类型,所以在语法层面上来说,没有错误。

        但很抱歉的是,如果这么写,无法得到真正的转换。(尽管这是函数的问题,而非模板)

      模板的实例化(确定参数的类型)

        模板的实例化分为两类:隐式实例化,显示实例化。

       隐式实例化

   隐式实例化我们实际上已经演示过了,上图的Swap就是隐式实例化。

   在函数编译的时候,编译器会通过我们传入的参数的类型,来“猜”对应的虚拟类型是什么。

   如果发现猜不到类型(如对着同一个虚拟类型传入了两个不同类型的参数),编译器会开始查看是否有其他的重载函数。因为除了模板,普通函数也是可以重载的。

    这两步都做完,如果还找不到,那么编译器就会报错。

      

       显式实例化

        

template<class T1,class T2>
void Swap(T1& a, T2& b) {
	T1 tmp=a;
	a = b;
	b = tmp;
}

int main() {
	int a = 10;
	double b = 9.9;
	Swap<int,double>(a, b);
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	return 0;
}

   观察调用Swap的时候,我们在Swap函数后加入了<int,double>,代表第一个参数是int,第二个参数是double(但仍然需要定义两个虚拟类型)

        如果只需要一个参数类型,也可以这么写:

Swap<int>(a,b);

        这就意味着将b强制类型转换为int。

        当显式实例化不成功,编译器会尝试自己匹配类型(隐式实例化)。

       实例化顺序

   1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

   2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。

        最容易的理解方式是:

        模板是参数相同的同名函数的一个总和,这意味着普通函数,也可能是某一模板的实例化。

        模板实例化出一个函数是需要消耗资源的,编译器会优先使用已有的模板函数,但如果在匹配上,模板实例化出的函数更匹配,那么就会用模板。这和我们之前提到的引用返回还是传值返回的原则很像,先达成目的,再考虑效率

   需要注意的一点是:

   模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

三、类模板和模板类

        类模板,本质还是模板,只不过是某一种类的模板,因而称为类模板。其实例化产生的类,称为模板类。这两个名字经常容易混淆,实际上只需要看后缀,一个本质是模板,一个本质是类。

        类模板的定义格式如下:

template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
};

         需要注意的是,类模板中函数在类外定义时,需要加模板参数列表。(声明与定义分离的情况),所以在练习的时候,为了避免不必要的麻烦,尽量在类内定义。工作中可能因为需要时常维护,导致需要分离定义。

// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
 if(_pData)
 delete[] _pData;
 _size = _capacity = 0;
}

      类模板的实例化

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

// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

        (这里大写的原因,仍然是因为vector在C++中有特殊含义,后续会讲到)。

        本篇内容到此结束,谢谢大家的观看!

        觉得写的还不错的可以点点关注,收藏和赞,一键三连。

        我们下期再见~

        往期栏目:    

        C++学习指南(一)——C++入门基础-CSDN博客

        C++学习指南(二)——类和对象-CSDN博客    

        

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值