嵌套重载以及模板特化

本文探讨了在C++中实现链式栈时遇到的重载`<<`运算符的问题,详细分析了导致链接错误的原因。通过研究发现,问题源于友元函数的模板特化。在VS2013和Linux平台的不同编译要求下,正确的做法是在类声明中使用模板特化`friend ostream& operator<< <Type>(ostream& ou, ListNode<Type>& r)`和`friend ostream& operator<< <Type>(ostream& out, stack<Type>& R)`,以避免链接错误。此外,文章建议在某些情况下可以将类的成员设为公有,简化编程复杂性。" 111450432,10294160,Python实现MD5与SHA256可视化哈希加密工具,"['Python', '前端开发', '加密算法']
摘要由CSDN通过智能技术生成

我在用c++实现一个链式栈的时候,想利用其特性实现一个”简单“ << 的重载,却不料这个重载却是如此的艰辛,我用的是VS2013,编译器一直出现链接错误,我检查了好久,认为没有错误,而其中大有文章。

代码如下:

#pragma once
#include <iostream>
#include <fstream>
#include <assert.h>
using namespace std;
template<class Type>
class stack;
//template<class Type>
//class ListNode;
//template<class Type>
//ostream& operator<<(ostream& ou, ListNode<Type>& r);
template<class Type>
class ListNode
{
	friend class stack<Type>;
public:
	ListNode() :data(Type()), link(NULL)
	{}
	ListNode(Type d, ListNode<Type>* next = NULL) :data(d), link(next)
	{}
	~ListNode()
	{}
	friend ostream& operator<< <Type>(ostream& ou, ListNode<Type>& r);
	friend ostream& operator<< <Type>(ostream& out, stack<Type>& R);
private:
	Type                data;
	ListNode<Type>*      link;
};
//template<class Type>
//ostream& operator<<(ostream& out, stack<Type>& R);
template<class Type>
class stack
{
public:
	stack()
	{
		top = NULL;
	}
	~stack()
	{
		Destroy();
	}
public:
	bool Empty()
	{
		return top == NULL;
	}
	void Push(Type x)
	{
		if (Empty())
		{
			top = new ListNode<Type>(x);
		}
		else
		{
			top = new ListNode<Type>(x, top);
		}
	}
	/*void Show()
	{
		if (Empty())
		{
			return;
		}
		else
		{
			ListNode<Type>* cur = top;
			while (cur != NULL)
			{
				cout << cur->data << " ";
				cur = cur->link;
			}
		}
		cout << endl;
	}*/
	void Pop()
	{
		if (Empty())
		{
			return;
		}
		else
		{
			ListNode<Type>* rm = top;
			top = top->link;
			delete rm;
		}
	}
	void Pop(Type& e)
	{
		if (Empty())
		{
			return;
		}
		else
		{
			e = top->data;
			ListNode<Type>* rm = top;
			top = top->link;
			delete rm;
		}
	}
	Type Gettop()
	{
		if (Empty())
			return NULL;
		else
			return top->data;
	}
	int Length()
	{
		int count = 0;
		if (Empty())
		{
		}
		else
		{
			ListNode<Type>* cur = top;
			while (cur != NULL)
			{
				count++;
				cur = cur->link;
			}
		}
		return count;
	}
	void Destroy()
	{
		if (Empty())
		{
			return;
		}
		else
		{
			ListNode<Type>* rm = top;
			while (top != NULL)
			{
				rm = top;
				top = top->link;
				delete rm;
			}
		}
	}
  friend ostream& operator<< <Type>(ostream& out, stack<Type>& R);
private:
	ListNode<Type>*  top;
};
template<class Type>
ostream& operator<<(ostream& ou, ListNode<Type>& r)
{
		ou << r.data;
		return ou;
}
template<class Type>
ostream& operator<<(ostream& out, stack<Type>& R)
{
	out << "top:";
	ListNode<Type>* cur = R.top;
	while (cur != NULL)
	{
		out << *cur;
		out << " ";
		cur = cur->link;
	}
	out << "base";
	out << endl;
	return out;
}


测试代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"

int main()
{
	stack<int> st;
	st.Push(23);
	st.Push(24);
	st.Push(25);
	st.Push(26); 
	cout << st;
	st.Push(27);
	cout << st;
	int a=st.Gettop();
	cout << a << endl;
	st.Pop();
	cout << st;
	return 0;
}


我刚刚开始的时候两个友元函数是这样定义的:

friend ostream& operator<<(ostream& ou, ListNode<Type>& r);
friend ostream& operator<<(ostream& out, stack<Type>& R);

这样也算合情合理吧,可是运行起来却总是出现链接错误,找了很久很久没有发现。

我看了c++primer上讲述的,意思是一个友元函数若是要被一个类的对象所使用,必须提前声明它,所以我提前定义了,但最后证明不是主要原因。实际上我在代码中注释的那些都跟编译器有关,在vs2013下不需要(但加上并没有错),但是在linux平台下是必须要的。

最终问题出现在没有特化,正确的做法是类里面声明时候写成 friend ostream& operator<< <Type>(ostream& ou, ListNode<Type>& r);
      friend ostream& operator<< <Type>(ostream& out, stack<Type>& R);

因为友元函数并不是类的成员,所以需要特化为<Type>,否则会产生链接错误,即找不到重载的<<符号。

最后,我觉得我们在以后的编程中,可以把ListNode类的成员全部设为共有,这样有利于对其中的数据的访问,而且不需要许多复杂的处理,在上面例子中,为了访问ListNode的数据,声明了stackwei其友元类,而且在其中声明了 friend ostream& operator<< <Type>(ostream& out, stack<Type>& R);,若将ListNode暴露出来则没有这些复杂的处理。而主要类stack封装起来,这样实现方法照样可以得到很好的保护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值