template中友元类的使用
今天尝试用template完成一个循环链表,期间几费周折,将遇到的问题记录一下。这是最后完成的circleList.hpp文件。
#ifndef CIRCLELIST_HPP_ #define CIRCLELIST_HPP_ template <typename T> class CircleList; template <typename T> class CNode { private: T elem; CNode<T>* next; friend class CircleList<T>; }; template <typename T> class CircleList { public: CircleList(); ~CircleList(); bool empty() const; const T& front() const; const T& back() const; void advance(); void add(const T& e); void remove(); private: CNode<T>* cursor; }; template<typename T> CircleList<T>::CircleList():cursor(NULL){ } template<typename T> CircleList<T>::~CircleList() { while(!empty()) remove(); } template<typename T> bool CircleList<T>::empty() const { return cursor == NULL; } template<typename T> const T& CircleList<T>::back() const { return cursor->elem; } template<typename T> const T& CircleList<T>::front() const { return cursor->next->elem; } template<typename T> void CircleList<T>::advance() { cursor = cursor->next; } template<typename T> void CircleList<T>::remove() { CNode<T>* old = cursor->next; if(old == cursor) cursor = NULL; else cursor->next = old->next; delete old; } template<typename T> void CircleList<T>::add(const T& e) { CNode<T>* v = new CNode<T>; v->elem = e; if(cursor == NULL) { v->next = v; cursor = v; } else { v->next = cursor->next; cursor->next = v; } } #endif
example文件circleTest.cpp
#include <iostream> #include <string> #include "circleList.hpp" using namespace std; int main() { CircleList<string> list; if(list.empty()) cout << "empty" << endl; list.add("hello"); list.add("world"); list.add("come on"); cout << list.front() << endl; cout << list.back() << endl; return 0; }
遇到的问题:
(1)开始时,将circleList.hpp 中的类声明和类定义分开放,即类定义在circleList.cpp中,声明在circleList.hpp中。报错,出现undefined reference to的错误。因此,需要复习下类模板的声明、定义和使用。
(a) 将c++模板的声明和定义都放在同一个文件,如.h和.cpp文件中,使用的时候,#nclude "模板文件名.h或.cpp"即可
(b) 将c++模板的声明和定义分别放在.h和.cpp文件中,并在.cpp文件中#include .h 文件,使用时,直接#include .cpp文件
小结:只有将模板.cpp文件同调用.cpp文件,才能确定类的真正类型,不出现undefined reference to一类的链接错误。
(2)代码中标红的地方需要注意,容易忽略。
(3)在模板类中声明友元类,有两种声明方法
(a) 如circleList.hpp中所示,
template <typename T> class CircleList; template <typename T> class CNode { private: T elem; CNode<T>* next; friend class CircleList<T>; };
此种声明方式,只有当CircleList中数据类型与CNode中的数据类型相同时,友元功能才生效。
(b)另一种声明方式:
template <typename T> class CNode { private: T elem; CNode<T>* next; template<typename T1> friend class CircleList; };
此种声明方式,两个模板类的T和T1不能相同,若相同则出现类型重复的错误。按此种声明方式,无论CircleList中的数据类型是否与CNode相同,都可以访
问CNode类的private成员。
(4)在定义template时,typename和class的区别:在声明时没有区别,typename在使用时有需要注意的地方,未完待续...