![Visual C++从入门到精通(第5版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/338/27563338/b_27563338.jpg)
5.2 类模板
函数模板为函数的参数、返回值等提供了动态参数化的机制,使用户能够动态设置函数的参数类型和返回值类型;而类模板能够为类的数据成员、成员函数的参数、返回值提供动态参数化的机制,使用户可以方便地设计出功能更为灵活的类。本节将介绍有关类模板的相关知识。
5.2.1 类模板的定义及应用
在介绍类模板之前,先来设计一个简单的单向链表。链表的功能包括向尾节点添加数据、遍历链表中的节点、在链表结束时释放所有节点,代码如下。
【例5.38】 定义单向链表。(实例位置:资源包\TM\sl\5\18)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P178_41828.jpg?sign=1738878713-r77JaupXTml8FLs3qZjIW5F5Wl7NVTPb-0-03608fa841010d3504e53ad8620124a9)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P179_42038.jpg?sign=1738878713-sVqJCVFme6TAmQ2bdEg9yF87NL8CXDUj-0-846f2dbf5078781318dba3ec637cde02)
下面定义一个链表对象,向其中添加节点,并遍历链表节点。
【例5.39】 遍历单向链表。(实例位置:资源包\TM\sl\5\18)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P179_42218.jpg?sign=1738878713-j9Vwy3ujdpppvbzcREhWEg9OWA4nF19m-0-a9c638e7f0ec873977a33839f2d74c89)
执行上述代码,结果如图5.18所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P180_42448.jpg?sign=1738878713-Jql2tPVM1YAVCixy3aUUSW0OufEnc3H8-0-7a0cd575fae34ec53b4d70c660c74e1a)
图5.18 简单链表
分析上述代码中定义的链表类CList,一个最大的缺陷就是链表不够灵活,其节点只能是CNode类型。为了让CList能够适应各种类型的节点,一个最简单的方法就是使用类模板。类模板的定义与函数模板类似,以关键字template开始,其后是由尖括号<>构成的模板参数。下面重新修改链表类CList,以类模板的形式进行改写。
【例5.40】 利用类模板设计链表类。(实例位置:资源包\TM\sl\5\19)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P180_42295.jpg?sign=1738878713-TAgbaVZFWaLONW6chlzhY4ug0Yydp7Em-0-df2c755647c0613c515470882a7a72e2)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P181_42467.jpg?sign=1738878713-Rg8DL9pIgHkcuHIzF1Pw6tl5GZ52coHg-0-e7f9b559d9b01f7fde982315e790c025)
注意
每个模板参数必须由class或typename标识,不能够利用一个class或typename关键字定义多个模板参数。
上述代码利用类模板对链表类CList进行了修改,实际上是在原来链表的基础上将链表中出现CNode类型的地方替换为模板参数Type。下面再定义一个节点类CNet,演示模板类CList是如何适应不同的节点类型的。
【例5.41】 演示类模板适应不同的节点类型。(实例位置:资源包\TM\sl\5\19)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P181_42642.jpg?sign=1738878713-8sHqCmFX2smnqkbflDkuKrgqnQLqAkud-0-c8cb9232cf2ec9a87e1a49f72ed545ed)
执行上述代码,结果如图5.19所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P182_42830.jpg?sign=1738878713-KDvbphurHVpvJz2EUYJtQ0OrnYzvgebK-0-c6b8426c3da38783a58453a4162e6777)
图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)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P183_42861.jpg?sign=1738878713-5HJIeNmcXahAI65OiqmWfhHWeLzsd9TO-0-c1956a2e5d8eddbed47c7bebf3e2b9ae)
下面定义两个类模板实例,分别设置并访问各自的静态数据成员。代码如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P183_42941.jpg?sign=1738878713-LGbrY0QumSrb0O3iddAaBFX3IrXm128Y-0-cdae77284d57d892b77039d96e49b822)
执行上述代码,结果如图5.20所示。
从图5.20中可以发现,类模板实例nodelist和netlist均有各自的静态数据成员。但是,对于同一类型的类模板实例,其静态数据成员是共享的。
【例5.43】 同一类型的类模板实例,其静态数据成员是共享的。(实例位置:资源包\TM\sl\5\21)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P183_42991.jpg?sign=1738878713-jt1AZncg06gPLUlCtsR1jWKyk48y8gVr-0-856f899490d2099419274a64882ac9e2)
执行上述代码,结果如图5.21所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P184_43111.jpg?sign=1738878713-pV5pzLbDdPnVqoeR7aJ0e7O3PS72Oiww-0-1b2eedbea4d0a608c91e49d5ca64e9ad)
图5.20 类模板静态数据成员
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P184_43112.jpg?sign=1738878713-qQN6QlwzcbgNOr4FfCeks1WXur2v2bMT-0-a6dce1a670928cacc58f245b913571ec)
图5.21 静态数据成员
从图5.21中可以发现,类模板实例nodelist和list共享静态数据成员,因为它们的模板类均为CNode。