5.2 类模板
函数模板为函数的参数、返回值等提供了动态参数化的机制,使用户能够动态设置函数的参数类型和返回值类型;而类模板能够为类的数据成员、成员函数的参数、返回值提供动态参数化的机制,使用户可以方便地设计出功能更为灵活的类。本节将介绍有关类模板的相关知识。
5.2.1 类模板的定义及应用
在介绍类模板之前,先来设计一个简单的单向链表。链表的功能包括向尾节点添加数据、遍历链表中的节点、在链表结束时释放所有节点,代码如下。
【例5.38】 定义单向链表。(实例位置:资源包\TM\sl\5\18)
下面定义一个链表对象,向其中添加节点,并遍历链表节点。
【例5.39】 遍历单向链表。(实例位置:资源包\TM\sl\5\18)
执行上述代码,结果如图5.18所示。
图5.18 简单链表
分析上述代码中定义的链表类CList,一个最大的缺陷就是链表不够灵活,其节点只能是CNode类型。为了让CList能够适应各种类型的节点,一个最简单的方法就是使用类模板。类模板的定义与函数模板类似,以关键字template开始,其后是由尖括号<>构成的模板参数。下面重新修改链表类CList,以类模板的形式进行改写。
【例5.40】 利用类模板设计链表类。(实例位置:资源包\TM\sl\5\19)
注意
每个模板参数必须由class或typename标识,不能够利用一个class或typename关键字定义多个模板参数。
上述代码利用类模板对链表类CList进行了修改,实际上是在原来链表的基础上将链表中出现CNode类型的地方替换为模板参数Type。下面再定义一个节点类CNet,演示模板类CList是如何适应不同的节点类型的。
【例5.41】 演示类模板适应不同的节点类型。(实例位置:资源包\TM\sl\5\19)
执行上述代码,结果如图5.19所示。
图5.19 类模板
说明
类模板CList虽然能够使用不同类型的节点,但是对节点的类型是有一定要求的。节点类必须包含一个指向自身的指针类型成员m_pNext,因为在CList中访问了m_pNext成员。节点类中必须包含数据成员m_Data,其类型被限制为数字类型或有序类型。实际上m_Data成员可以是任意类型,只是在CList类的PassList方法中,笔者为了演示遍历链表节点,使用了“printf("%4d",pTmp-> m_Data);”语句输出节点数据,导致m_Data只能是数字类型或有序类型。
5.2.2 定义类模板的静态数据成员
在类模板中用户也可以定义静态的数据成员,只是类模板中的每个实例都有自己的静态数据成员,而不是所有的类模板实例共享静态数据成员。为了说明这一点,笔者对类模板CList进行简化,向其中添加一个静态数据成员,并初始化静态数据成员。
【例5.42】 在类模板中使用静态数据成员。(实例位置:资源包\TM\sl\5\20)
下面定义两个类模板实例,分别设置并访问各自的静态数据成员。代码如下:
执行上述代码,结果如图5.20所示。
从图5.20中可以发现,类模板实例nodelist和netlist均有各自的静态数据成员。但是,对于同一类型的类模板实例,其静态数据成员是共享的。
【例5.43】 同一类型的类模板实例,其静态数据成员是共享的。(实例位置:资源包\TM\sl\5\21)
执行上述代码,结果如图5.21所示。
图5.20 类模板静态数据成员
图5.21 静态数据成员
从图5.21中可以发现,类模板实例nodelist和list共享静态数据成员,因为它们的模板类均为CNode。