我在用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封装起来,这样实现方法照样可以得到很好的保护。