嵌套类实现链表类模板:
一. 前置声明:Node类作为一个嵌套类包含在Link类中,由于编译器是从上往下进行扫描,所以,在这里我们要前面使用Node是需要告诉编译器我已经定义了这个类,需要在前面进行声明一下。
template<typename T = int>
class Link
{
public:
class Node;//在前面使用到Node类,需要前置声明
Link()
{
_phead = new Node();
}
~Link()
{
Node*pcur = _phead;
while (pcur != NULL)
{
_phead = _phead->_pnext;
delete pcur;
pcur = _phead;
}
}
void inserthead(const T&val)
{
Node *ptmp = new Node(val);
ptmp->_pnext = _phead->_pnext;
_phead->_pnext = ptmp;
}
Node * queryNode(const T&val);
void show();
private:
class Node
{
public:
Node(T data = T()) :_data(data), _pnext(NULL){}
T _data;
Node *_pnext;
};
Node *_phead;
};
二. typename的双重作用:
2.1 不用说,第一个作用就是用来定义模板参数类型的;
template<typename T > or template<class T > all is ok!
2.2 指定、告诉编译器后面的名称是一个类型。
在上面代码的基础上,我们将Node*queryNode(const T&val);实现在类外
template<typename T>
Node * Link<T>::queryNode(const T&val)
{
}
进行编译:
error C2065: “T”: 未声明的标识符
error C2923: “Link”: 对于参数“T”,“T”不是有效的 模板 类型变量
error C2509: “queryNode”: 成员函数没有在“Link”中声明
这样似乎有问题,由于Node类是定义在Link类的作用域中的,所以我们应该在Node前面加上Link的作用域,这样编译器更好的找到,而不是默认去全局找。
template<typename T>
Link<T>::Node * Link<T>::queryNode(const T&val)
{
}
编译以后还是无法通过:
警告 1 warning C4346: “Link<T>::Node”: 依赖名称不是类型
然后又跟一大堆错误。
它居然说我的Node不是一个类型
我们需要在Node的前面加上typename,告诉编译器Node是Link作用域下面的一个类型,函数返回Node*这样的一个类型指针…而此时编译器根本不知道Link是个什么东西,因为它没有实例化过Link
Link<T>::Node * Link<T>::queryNode(const T&val)
分析:
由于我们并没有进行显示的实例化,所以编译器根本不知道Link::Node *
中的Link是个什么东西,更不用说Link作用域下的Node和其他的数据是个什么东西
所以,typename就是告诉编译器Link是个类,Node是Link类作用域下的一个类型,
这样编译器就不会“胡思乱想”了。
正确写法:
template<typename T>
typename Link<T>::Node * Link<T>::queryNode(const T&val)
{
//......
}
三、STL中遍地都是typename:
template<class _Myvec>
class _Vector_const_iterator
: public _Iterator012<random_access_iterator_tag,
typename _Myvec::value_type,
typename _Myvec::difference_type,
typename _Myvec::const_pointer,
typename _Myvec::const_reference,
_Iterator_base>
{ // iterator for nonmutable vector
public:
typedef _Vector_const_iterator<_Myvec> _Myiter;
typedef random_access_iterator_tag iterator_category;
typedef typename _Myvec::value_type value_type;
typedef typename _Myvec::difference_type difference_type;
typedef typename _Myvec::const_pointer pointer;
typedef typename _Myvec::const_reference reference;
typedef typename _Myvec::pointer _Tptr;
......
};
比如:typedef typename _Myvec::const_reference reference;
- _Myvec是一个模板,在编译器还没有实例化它之前,编译器并不知道_Myvec是个啥,里面到底有哪些内容,更不用说_Myvec作用域下的const_reference是个什么东西,所以需要typename告诉编译器这是个类型。