类模板基础(二)嵌套类的前置声明与typename的双重作用

嵌套类实现链表类模板:

一. 前置声明: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告诉编译器这是个类型。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值