作者 | 梁唐
大家好,我是梁唐。
这是EasyC++系列的第88篇,我们继续来聊聊类模板
虽然继承和多态非常好用,但很多时候依然不能满足我们对复用代码的需要。比如有的时候,我们希望存储一些数据,对于数据的类型并不关心,比如int
和double
类型的数据我们希望按照同样的逻辑存储。
如果大家学过Python会知道,Python是隐式类型语言,在代码逻辑当中并不关心变量的类型。比如同样一个list,对于int
还是double
或者是其它任何类型都是一样的处理。
但因为C++是显式类型语言,所以对于不同的类型我们需要单独创建一份代码,这显然就会非常麻烦。这个时候我们就可以使用类模板来完成需求,类模板有些近似于Java当中的泛型。但Java中的泛型和C++的类模板在底层运行逻辑有些区别,只是功能上近似,所以严格来说也不能混为一谈。感兴趣的同学可以去搜索研究一下,这个问题细究起来非常硬核。
所谓类模板,即参数化类型,即能够将类型名作为参数传递给接收方来创建函数或者是类。我们在使用C++刷题的时候经常用到,比如最经典的创建一个int
类型的vector
:vector<int> vt;
。
这是使用的STL当中的模板类,如果我们要自己创建模板类呢,应该怎么做?接下来我们就来深入探讨一下这个问题。
我们以Stack
类为例,对于一个确定类型的Stack
,我们的代码如下:
typedef unsigned long Item;
class Stack {
private:
enum {MAX = 10};
Item items[MAX];
int top;
public:
Stack();
bool isempty() const;
bool isfull() const;
bool push(const Item& item);
bool pop(Item & item);
}
采用模板时,我们将使用模板定义替换Stack
声明,使用模板成员函数替换Stack
的成员函数,和模板函数一样,模板类也是以下面的代码开头:
template <class Type>
关键字template
告诉编译器,这里将要定义一个模板。尖括号中的内容相当于函数的参数列表,可以将class
看成是参数的类型名,该参数是一个变量类型,Type
是它的名称。
这里的class
并不意味着我们一定要传入一个类类型,而只是一个通用的类型说明符。较新的C++版本当中,我们可以使用typename
来代替,这样可以避免歧义。
这里的Type
是常规写法,也有很多程序员喜欢写成T
,这只是一个参数名,怎样写都是可以的。
同样,我们也可以使用模板成员函数代替原有类的方法,每个函数开头都需要相同的模板声明打头,另外还需要将类限定符从Stack::
替换成Stack<T>
。
template <typename T>
bool Stack<T>::push(const T& item) {
return false;
}
如果我们是在类声明当中以内联的形式定义的方法,那么可以省略模板前缀和类限定符。
最后,需要注意的是,当我们使用类模板的时候,需要将类的声明和定义写在一个.h
文件当中。至于为什么需要这样操作的原因比较复杂,我们将会单独放在下一篇文章当中进行阐述。