模板类与友元函数:关于LNK1120和LNK2019报错

因为最近呢开始用清华大学出版社的那本数据结构自学,真正脱离书本写了一个队列,还是出了点问题的。

template 
class LQueue
{
public:
	LQueue();
	~LQueue();
	bool EnQueue(const T& x);
	bool DeQueue(T& x);
	int getSize() const;
	bool getHead(T& x) const;
	bool IsEmpty() const{ return head->link == NULL; }
	void makeEmpty();
	friend ostream& operator<< (ostream& out, LQueue& Q);
private:
	LinkNode* rear, * head;
};

template 
ostream& operator<< (ostream& out, LQueue& Q){
	LinkNode* current = Q.head->link;
	int i = 0;
	while (current != NULL){
		i++;
		out << "#" << i << ":" << current->data << endl;
		current = current->link;
	}
	return out;
};


当我在main中调用输出流的时候,竟然链接器报错!!

我一共只有这两个文件啊,一个头文件,一个main,我也知道模板类声明和实现要一起写的啊,然而,然而。。他就是报错,还linker的错误,又不能调试,又不知道具体问题在哪 ,无比奔溃,查了一个多小时,还和以前程序书上对了个比(我写的和书上略有差异,自己写的是带头节点的),愣是查不出,查报错,又是什么没找到实现,我我我我,我明明一起写了的啊!

在我临近崩坏之际,突然,灵光一闪,我把main中绝大部分代码注释,慢慢恢复注释来编译。yiu!终于最后锁定了问题!输出流函数!

在清华大学出版社数据结构(面向对象方法与C++语言描述)这本书中,它关于友元函数输出流的重载定义是在类声明之外的,同时在此前的例子里,并没有使用过这个输出流,因此我没有发现这个问题,由于模板函数只有实例化才会被编译,因此编译也不会报错。所以,所以,都是你这本书的锅啊啊啊!

然后我查了一下呢,将重载函数的定义甩进类的体内就好了。

***************关于原因**********************

参见英文原参考

怎么说呢,你在某处使用了这只可爱的模板类,友元函数呢也在某处神奇的定义着。在某时,你突然想用这个可爱的友元函数了,那么,在编译时,你的编译器在类定义中看见了这只友元函数,但你的编译器太瞎了,以为它的T实际上是int,而非一个模板函数。因此在你调用这个友元函数的时候,编译器召唤非模板函数,同样瞎瞎的链接器自然报错了啦。

****************解决***************************

除了上面说的直接甩进去之外呢,还可以呢,在类定义前预定义:

template class LQueue;  // pre-declare
template ostream& operator<< (std::ostream& out, const LQueue& Q);
类定义里面的呢这么写(注意中间加了一对尖括号,好奇用途原理中)

friend ostream& operator<< <> (ostream& out, const LQueue& Q);
实现直接就好了
ostream& operator<< (ostream& out, const LQueue& Q)
  {
    // ...
  }
就是这样,谢谢

哦对,一般模板类是尽可能绝不能加什么友元函数的,除非重载流

你可能感兴趣的:(数据结构学习中)