c++中模板类的使用

最近在数据结构的课程中很多周围的同学对模板类的使用抱有很大的困惑,看也能看懂,但写起来总是不明白……
那就首先得知道为什么要用模板。
假设我有一个方法

void swap(int& a,int& b)
{
    int c = a;
    a = b;
    b = c
}

作用是交换两个参数,实现起来也很简单,
乍看上去挺好的,但我现在有另外一个需求,我需要交换两个double,这时候你可能会说,再重载一个void swap(double& a,double& b);不就行了
但是在这里我们观察可以发现,swap函数的实现,其实与它的参数的类型是无关的。也就是,double,int,或者别的什么,它的实现方法都是c=a;a=b;b=c;
所以,就有了模板这种东西。模板用template声明,这里的class可以用typename替换,两者完全一样。T是我们给这种临时数据类型取的名字,也可以随便改。在模板的作用下,这个方法可以改成

templateT>
void swap(T&a,T&b)
{
    T c = a;
    a = b;
    b = c;
}

也就是说,这里的T相当于我们定义了一种新的数据类型(class并不代表我们定义了一个类),只是这种数据类型很特殊,可以随你传的值变化。当你调用这个函数的时候向其中传入的是什么类型,T就会变成什么类型。

注意! 但是,虽然T可变,但是一旦确定下来之后,它就是确定的,比如swap里不能传一个int,一个double,必须统一。
template<class T>作用域只有下面的一个代码块,也就是一个方法体或者一个类。在swap之下再用T,是会报错的。

上面是模板最简单的用法,作用于单个函数,适用于算法一样,但类型不一样,且算法与类型无关的情况。

对类使用模板

类似于上面的情况,在创建一些类的时候我们也有使用模板的需要。比如,我建立了一个链表的类Chain,和链表节点类ChainNode。

class ChainNode
{
private:
    ChainNode();
    int data;
    ChainNode *next;
};

在定义类ChainNode时,我们需要保存两个值,一个是数据,一个是指向下一个ChainNode的指针。我们创建这个链表类,一定是希望它适合多种场合,可重复利用,但是定义ChainNode时我们必须要指定数据的保存类型。也就是说,ChainNode定义时data的类型是int,那Chain就只能保存int,要想保存double,那我们似乎只能重写Chain类,最好的情况也是重写ChainNode类。

但我们现在不需要这么麻烦,我们有模板这个好用的工具,现在看以下代码:

template <class T>
class ChainNode
{
private:
    ChainNode();
    T data;
    ChainNode *next;
};

这样,只需要我们在使用时,如下声明ChainNode

ChainNode<int> node1;
ChainNode<double> node2;

即可方便地使用ChainNode的int版和double版。注意如上代码,不同于函数是自动判断,带模板的类在使用时需要显式指定。当ChainNode后面跟< int>时,你可以简单地理解为把上面的ChainNode类中所有的T替换成了int。

需要注意的是,当我们在类的外部实现方法(这是合理而必要的)时,不同于不使用模板时的定义

ChainNode::ChainNode()
{
    data = 0;
    next = 0;
}

我们现在需要

template <class T>
ChainNode<T>::ChainNode()
{
    data = 0;
    next = 0;
}

不论该函数是否使用了模板。

在new出带有模板的类的对象的时候,也有稍许不同,

ChainNode<int> *node = new ChainNode<int>();

如果ChainNode类有一个静态方法sMethod(),调用时:

ChainNode<int>::sMethod();

另外,我们现在Chain类是需要保存一个ChainNode的指针first指向链表的头节点,那这时候怎么做呢?
答案是把Chain类也用上模板。

template<class U>//防止跟上面的T搞混表不清意思
class Chain{
public:
    //上略
private:
    ChainNode *first;
    //下略
};

这样意思就很清楚了,ChainNode声明的时候需要指定类型?那我就再指定个模板给你先拿着吧,等我使用Chain时,我指定好U这个类型具体是什么,自然也就把U传到ChainNode< U>里了。

其实根据这个思路,我们甚至可以这样用

ChainNodeint>>//保存 保存int数据的节点 的节点

类似二维数组,这叫做递归调用模板

模板还有一些更高级的用法,这里就不介绍啦,大家自行摸索吧

你可能感兴趣的:(c++)