今天尝试用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在使用时有需要注意的地方,未完待续...