2015年2月16日 周一雨
很久没有更新笔记,上一篇博客介绍了什么是模板,主要是告诉大家函数模板。今天我们就再来一起看一看什么是类模板。
函数模板就是把函数作为模板去使用,类模板当然也就是把类作为模板去使用。
——————————————————————分割线————————————————————————
一、什么是类模板? 模板的目的就是为了淡化数据类型的要求,作出通用数据类型的模板。类中的成员变量和成员函数都牵涉到了数据类型。
在成员函数、成员变量以及基类中包含有类型参数的类称为类模板。
【模板/STL|【c++模板笔记二】类模板的介绍以及使用方法】和函数模板一样,类模板只是一个模板,并不是真正的类。
二、类模板的定义和使用
1.定义语法:
template
class 类模板名 [: public 基类] { ... };
和函数模板一样,都在上方加上一句template声明模板参数列表。然后在类中就可以使用这些类型形参了。 2.使用语法:
类模板名<类型实参1, 类型实参2, ...> 对象 (构造实参);
类模板名<类型实参1, 类型实参2, ...>& 对象引用 = ...;
类模板名<类型实参1, 类型实参2, ...>* 对象指针 = ...;
我们一起来看个例子大家就懂了: #include
文章图片
A就是一个类模板,a1为A实例化(int)的对象,a2则是一个对象指针,a3是一个对象引用。a4是double实例化A模板的对象。
三、类模板与函数模板的异同
1.类模板和函数模板都需要二次编译
请大家参看: 【c++模板笔记一】。我们看到函数模板的原理是二次编译。同样的类模板也需要二次编译。 类模板 -- 实例化为 ->类 -- 实例化为 -> 对象
类模板先在编译期的时候实例化为类,再在运行的时候实例化为真正的对象。其实类中的这个二次编译也叫二次实例化。
2.类不能隐式推断
我们在上一篇中讲到了函数模板的隐式推断,但是类模板却不能隐式推断。
文章图片
我们可以看到,如果我们给类模板不提供模板参数列表的话,我们可以看见比编译器报错了(a之前缺少模板参数)
四、类模板的实例化
1.用类去实例化模板
上面说过,类模板的二次编译,其实也是二次实例化。但是如果用一个类类型去实例化一个类模板的话,又要注意什么呢? 用类去实例化一个类模板,规则如下: 1)该类型需要满足模板中对类型化参数的调用规则。
2)对于那些不使用的调用规则,实例化类型可以不予支持。
#include
文章图片
我发现我们用int去实例化类模板A的话,调用show和fun成员函数都没有问题。如果我们用Student这个类去实例化模板的话可不可以呢?我们发现,我们调用show函数时没有问题的。如果我们把30行的注释去掉的话,又会怎样?
文章图片
如果我们用Student类去实例化类模板A的话,如果调用成员函数fun的话, 程序就开始报错 了。m_data这个类的类型是Student类型的,如果要cout<
2.递归实例化
我们一起用模板做一个数组模板类,这种模板能存储任何数据类型。 #include
文章图片
Array是一个类模板,可以实例化为多种类型的类,成员变量为含有3个元素的数组,可以把这个实例化后的类用来当做含有3个元素的数组使用。我们实例化了一个int类型的Array类,定义了一个对象。这个对象就是一个含有3元素的一维数组。 那我们如何去实例化一个3x3的二维数组类,就需要用到递归实例化,如:Array >。这就是递归实例化。 我们把来一起用代码来实现: #include
文章图片
这种实例化还是很实用的,可以适用于很多种递归的数据结构(如二位数组,树等等递归结构)。
五、类模板中的静态成员变量 我们都知道类中可以包含静态数据(静态成员变量和静态成员函数),不懂的请看我的: 【c++笔记七】。那类模板能不能也包含静态数据呢?当然没有问题。 但是我们还是要注意点一点,模板不是真正的类,仅仅是模板而已。类模板的静态成员变量既不是一个对象一个,也不是一个模板一个,而是一个实例化类一个。我们一起来看代码: #include
文章图片
B类是一个普通类,有一个静态成员变量。静态成员变量需要初始化的,所以需要在类外进行初始化,初始化的语法如第13行。但是,A却是一个模板类,但是我们要如何去初始化这个模板类中的静态成员变量呢?
我们前面说过,类模板只是模不是类,不能当类去使用它。只有类才有作用域,所以无法直接在A后面跟上“::”作用域限定符。并且,声明m_data的类型是T,在类外的话没有这个T。所以,初始化模板的静态成员变量应该这么去写: #include
文章图片
六、局部特化 记得我们上一篇提到过模板重载吧?我们说过函数模板可以和普通函数构成重载关系。如: template
下面的那个普通函数Max和上面函数模板Max构成了重载关系。如果在类模板中也进行这样的重载,就会出现什么情况呢?
文章图片
编译器报错了,说13行的普通成员函数不能构成重载。那么怎么去解决这个问题呢?一个方法就是 全部特化。 #include
文章图片
我们可以看第14行到23行,就是模板A的 全局特化。用const char*去 特例化模板类A。 另外一种方法就是 局部特化。
#include
文章图片
第14行到17行,就是 局部特化。相比全部特化,省去很多事情。
七、类模板的缺省模板参数 我们经常看见函数有缺省参数,如int max(int a=10,int b=20)。 类模板其实也有缺省的模板参数,但是c++的98标准并没有这一东西,是在c++11标准中新引入的。我们看看代码就行: #include
文章图片
我们给类模板的模板参数指定默认的参数类型为double型。
————————————————————分割线———————————————————————— 类模板的知识就是这些,没有什么比较难的知识点,主要是大家懂了之后要会去使用,为以后的STL打个基础。 总结一下:首先我们介绍什么是类模板,怎么去定义和使用类模板。其次我们比较了类模板和函数模板的异同,然后我们讲解了类模板的实例化。再者我们讲了类模板的静态成员变量和局部特化。特别是要会使用局部特化。最后还讲了类模板的缺省参数,是一个非常有用的东西。
推荐阅读
- 模板/STL|【c++模板笔记一】模板的介绍及其重载
- C++|C++模板笔记六(类模板与继承;)
- 模板
- 模板|类欧几里得算法
- 模板|LOJ #2340. 「WC2018」州区划分(FMT子集卷积)
- 模板|FWT 模板
- C++|高精度加法 洛谷 P1601 A+B Problem(高精)
- 基础数据结构
- C++题解|【模板】迷宫#1