英文:
Question on overload non-member operator << in a linkedlist class in c++98
问题
Sure, here's the translated code you provided:
有人可以帮我解答这个问题吗?为了提供背景信息,我有三个类,`Account.h` 和 `Account.cpp`,`Node.h` 和 `Node.cpp`,`LinkedList.h` 和 `Linkedlist.cpp`,以及包含 `int main()` 的 `demo.cpp`。所有当前的函数都能正常工作,只有打印出链表的功能还没实现,这也是我的问题所在。
问题明确要求:
> 实现一个非成员重载的 `operator <<` 函数,使用 `Account` 中的 `operator <<`,允许你执行如下操作:
> `cout << MyLinkedList << endl;`
我从 `LinkedList.cpp` 和 `Account.cpp` 中复制了与这个问题相关的特定部分,因为如果我把所有代码都粘贴在这里,会太长了。
在 `LinkedList.cpp` 中,有一个未能正常工作的重载的 `operator <<` 函数,代码如下所示:请注意 `value_type` 是 `Account` 的 typedef。
```c++
#include "LinkedList.h"
    
LinkedList::value_type LinkedList::getCurrent() const {
    if (current != NULL) {
    	return current->getData();
    } else {
    	return value_type();
    }
}
    
ostream& operator << (ostream& out, const LinkedList& list) { // not working, compile error!
    value_type current = getCurrent();
    while (current != NULL) {
        out << "(" << acc.getName() << "," << acc.balance() << ")" << endl;
    }
    return out;
}
在 Account.cpp 中的代码如下:
ostream& operator << (ostream& out, const Account& acc)
{
    out << "(" << acc.getName() << "," << acc.balance() << ")" << endl;
    return out;
}
这些是我的 node.h 文件的类声明:
#ifndef TEKAAI_NODE
#define TEKAAI_NODE
#include "Account.h"
class Node
{
	public:
		// 外部可见的成员
		
		// 以下是成员函数
		
		// 使用 typedef 将 value_type 指定为 Account
		typedef Account value_type;
		
		// 默认构造函数
		
		Node();		
		
		// 参数构造函数
		
		Node(const value_type& initial_data, Node* initial_link);
		
		~Node();	// 析构函数
		
		void setNext(Node* n);
		
		void setPrevious(Node* p);
		
		Node* getNext() const;
		
		Node* getPrevious() const;
		
		// 数据的获取和设置
		// 前提条件:Current 已初始化
		// 后置条件:设置数据
		void setData(const value_type& i);
		
		// 前提条件:数据已初始化
		// 后置条件:返回存储的数据
		value_type getData() const;
		
	private:
		value_type data;	// 节点保存的数据
		Node* next; 		// 指向下一个节点的指针
		Node* previous;		// 指向前一个节点的指针
};
#endif
这些是我的 LinkedList.h 文件中的类声明:
#ifndef TEKAAI_LINKEDLIST_H
#define TEKAAI_LINKEDLIST_H
#include "Account.h"
#include "Node.h"
#include <iostream>
class LinkedList
{
    public:
		typedef Account value_type;
		// 外部可见的成员
		
		// 这些是成员函数
		
		// 构造函数
		    
		LinkedList();	
		
		// 析构函数
		
		~LinkedList();
		
		void addToHead(const value_type& account); 
		
		void addToTail(const value_type& account);
		
		void addCurrent(const value_type& account);
		
		value_type removeFromHead();
		
		value_type removeFromTail();
		
        value_type removeFromCurrent();
		
	    // 前提条件:链表包含节点
		// 后置条件:将当前节点移到头部 
	    void start();  
	    // 前提条件:链表包含节点
	    // 后置条件:将当前节点移到尾部
	    void end();
		
	    // 前提条件:链表包含节点
	    // 后置条件:将当前节点向右移动一个节点
	    void forward();  
		
	    // 前提条件:链表包含节点
	    // 后置条件:将当前节点向左移动一个节点
	    void back(); 
		
	    // 前提条件:链表包含节点
	    // 后置条件:返回当前节点存储的数据帐户的值
	    value_type getCurrent() const;
		
	    // 前提条件:链表已初始化,包含节点
	    // 后置条件:返回链表的长度
	    int length();
	
	private:
	    Node* head;
	    Node* tail;
	    Node* current;
};	
ostream& operator << (ostream& out, const LinkedList& list);
#endif	
正如你在上面的 LinkedList 类声明中看到的,我必须使用其中一个上面的函数之一来尝试打印我的链表。我想听听你的意见,是否可能使用上述 Account 中的重载 << 操作符以及其中一个函数来打印我的链表,正如问题所指定的那样。
谢谢。
另外请注意:只是想让你知道,我可以使用函数 Node* getHead() const; 打印我的链表,该函数返回头部,但我只是想知道是否可以在不使用 getHead() 函数的情况下打印链表。我想我们的讲师只是在玩弄我们,试图通过他的实验活动让我们失去理智。
<details>
<summary>英文:</summary>
Can anyone help me with this question please? For background information, I have three classes, `Account.h` with `Account.cpp`, `Node.h` with `Node.cpp`, `LinkedList.h` with `Linkedlist.cpp`, and `demo.cpp` that contains `int main()`. All of the current functions are working except for printing out the linkedlist, which is the basis of my question.
The question specifically says:
> Implement a non-member overloaded `operator <<` function, that uses the `operator <<` from `Account`, to allow you to perform an operation like:
>
> `cout << MyLinkedList << endl;`
I copied specific parts of my code related to this question from `LinkedList.cpp` and `Account.cpp` because it will be too long if I paste it all here.
Code from `LinkedList.cpp` with overloaded `operator <<` function "not yet working" is as shown below: Please note `value_type` is typedef for `Account`.
```c++
#include "LinkedList.h"
LinkedList::value_type LinkedList::getCurrent() const {
if (current != NULL) {
return current->getData();
} else {
return value_type();
}
}
ostream& operator << (ostream& out, const LinkedList& list) { // not working, compile error!
value_type current = getCurrent();
while (current != NULL) {
out << "(" << acc.getName() << "," << acc.balance() << ")" << endl;
}
return out;
}
Code from Account.cpp is as shown below:
ostream& operator << (ostream& out, const Account& acc)
{
    out << "(" << acc.getName() << "," << acc.balance() << ")" << endl;
    return out;
}
These are the class declarations for my node.h file:
#ifndef TEKAAI_NODE
#define TEKAAI_NODE
#include "Account.h"
class Node
{
	public:
		// members that are externally visible 
		
		// Below are Member functions
		
		// specifying value_type to Account using typedef
		typedef Account value_type;
		
		// Default constructor
		
		Node();		
		
		// Parameter Constructors
		
		Node(const value_type& initial_data, Node* initial_link);
		
		~Node();	//destructor
		
		void setNext(Node* n);
		
		void setPrevious(Node* p);
		
		Node* getNext() const;
		
		Node* getPrevious() const;
		
		// the data getters and setters
		// Pre-condition: Current has been initialized 
		// Post-condition: set data
		void setData(const value_type& i);
		
		// Pre-condition: Data has been initialized
		// Post-condition: returns stored data
		value_type getData() const;
		
	private:
		value_type data;	//the data held by the node
		Node* next; 		//a pointer to the next node
		Node* previous;		//a pointer to the previous node
};
#endif
These are the class declarations in my LinkedList.h file:
#ifndef TEKAAI_LINKEDLIST_H
#define TEKAAI_LINKEDLIST_H
#include "Account.h"
#include "Node.h"
#include <iostream>
class LinkedList
{
    public:
		typedef Account value_type;
		// Members that are externally visible
		
		// These are Member functions
		
		// Constructors
		    
		LinkedList();	
		
		// Destructor
		
		~LinkedList();
		
		void addToHead(const value_type& account); 
		
		void addToTail(const value_type& account);
		
		void addCurrent(const value_type& account);
		
		value_type removeFromHead();
		
		value_type removeFromTail();
		
        value_type removeFromCurrent();
		
	    // Pre-condition: LinkedList contains nodes
		// Post-condition: moves current to the head 
	    void start();  
	    // Pre-condition: LinkedList contains nodes
	    // Post-condition: moves current to the tail
	    void end();
		
	    // Pre-condition: LinkedList contains nodes
	    // Post-condition: moves current one node to the right
	    void forward();  
		
	    // Pre-condition: LinkedList contains nodes
	    // Post-condition: moves current one node to the left
	    void back(); 
		
	    // Pre-condition: LinkedList contains nodes
	    // Post-condition: returns the value of data account stored 
        // in current node
	    value_type getCurrent() const;
		
	    // Pre-condition: LinkedList is initialized, containing 
        // nodes
	    // Post-condition: returns the length of the list
	    int length();
	
	private:
	    Node* head;
	    Node* tail;
	    Node* current;
};	
ostream& operator << (ostream& out, const LinkedList& list);
#endif	
As you can see in LinkedList class declarations above,I have to work with them to try and print out my linkedlist. I would like to hear your thoughts if it is possible to print my linkedlist using one of the above functions while also using the overloaded << operator from Account as the question specified.
Thanks.
PLUS NOTE: Just to let you know that I can get to print my linkedlist using the function 'Node* getHead() const;' which returns head in overloading the << operator, but I was just looking for help if it is possible to print linkedlist without using the getHead() function. I guess our lecturer was just messing with us, trying to make us lose our minds with his lab activity.
答案1
得分: 2
First, your operator<<'s should be taking their 2nd parameters by const reference, not by value, eg:
ostream& operator << (ostream& out, const Account& acc)
ostream& operator << (ostream& out, const LinkedList& list)
Second, yes, it is possible to use the Account operator inside the LinkedList operator. You need something equivalent to the following (since you didn't provide full class declarations):
ostream& operator << (ostream& out, const LinkedList& list) {
    LinkedList::Node *cur = list.getFirst();
    while (cur != NULL) {
        out << cur->getData();
        cur = cur->getNext();
    }
    return out;
}
UPDATE: now that you have posted your LinkedList class declaration, I see that it does not offer anything like a getFirst() method. It has start() and forward() methods for iterating the list, but there is no method to indicate when the iteration has reached the end of the list.
So, you have a few options:
- add a new method to indicate that 
getCurrent()is safe to call: 
class LinkedList
{
    public:
        ...        
        bool hasCurrent() const;
        value_type getCurrent() const;        
        ...    
};  
bool LinkedList::hasCurrent() const {
return (current != NULL);
}
LinkedList::value_type LinkedList::getCurrent() const {
return current->getData();
}
ostream& operator << (ostream& out, LinkedList& list) {
list.start();
while (list.hasCurrent()) {
out << list.getCurrent();
list.forward();
}
return out;
}
- change your 
getCurrent()method to return theAccountobject by pointer instead of by value so that it can return aNULLpointer when the iteration is at the end of the list: 
class Node
{
    public:
        ...        
        value_type& getData();
        ...
};
LinkedList::value_type* LinkedList::getCurrent() {
    if (current != NULL) {
        return &(current->getData());
    } else {
        return NULL;
    }
}
ostream& operator << (ostream& out, LinkedList& list) {
    Account *cur;
    list.start();
    while ((cur = list.getCurrent()) != NULL) {
        out << *cur;
        list.forward();
    }
    return out;
}
- make the 
LinkedListoperator be afriendof theLinkedListclass so it can access the privateheadmember directly: 
class LinkedList
{
    public:
        ...
        friend ostream& operator << (ostream& out, const LinkedList& list);
        ...
    private:
        Node* head;
        ... 
};  
ostream& operator << (ostream& out, const LinkedList& list);
ostream& operator << (ostream& out, const LinkedList& list) {
    Node *cur = list.head;
    while (cur != NULL) {
        out << cur->getData();
        cur = cur->getNext();
    }
    return out;
}
英文:
First, your operator<<'s should be taking their 2nd parameters by const reference, not by value, eg:
ostream& operator << (ostream& out, const Account& acc)
ostream& operator << (ostream& out, const LinkedList& list)
Second, yes, it is possible to use the Account operator inside the LinkedList operator. You need something equivalent to the following (since you didn't provide full class declarations):
ostream& operator << (ostream& out, const LinkedList& list) {
    LinkedList::Node *cur = list.getFirst();
    while (cur != NULL) {
        out << cur->getData();
        cur = cur->getNext();
    }
    return out;
}
UPDATE: now that you have posted your LinkedList class declaration, I see that it does not offer anything like a getFirst() method. It has start() and forward() methods for iterating the list, but there is no method to indicate when the iteration has reached the end of the list.
So, you have a few options:
- add a new method to indicate that 
getCurrent()is safe to call: 
class LinkedList
{
    public:
        ...        
        bool hasCurrent() const;
        value_type getCurrent() const;        
        ...    
};  
bool LinkedList::hasCurrent() const {
return (current != NULL);
}
LinkedList::value_type LinkedList::getCurrent() const {
return current->getData();
}
ostream& operator << (ostream& out, LinkedList& list) {
list.start();
while (list.hasCurrent()) {
out << list.getCurrent();
list.forward();
}
return out;
}
- change your 
getCurrent()method to return theAccountobject by pointer instead of by value so that it can return aNULLpointer when the iteration is at the end of the list: 
class Node
{
    public:
        ...        
        value_type& getData();
        ...
};
LinkedList::value_type* LinkedList::getCurrent() {
    if (current != NULL) {
        return &(current->getData());
    } else {
        return NULL;
    }
}
ostream& operator << (ostream& out, LinkedList& list) {
    Account *cur;
    list.start();
    while ((cur = list.getCurrent()) != NULL) {
        out << *cur;
        list.forward();
    }
    return out;
}
- make the 
LinkedListoperator be afriendof theLinkedListclass so it can access the privateheadmember directly: 
class LinkedList
{
    public:
        ...
        friend ostream& operator << (ostream& out, const LinkedList& list);
        ...
    private:
        Node* head;
        ... 
};  
ostream& operator << (ostream& out, const LinkedList& list);
ostream& operator << (ostream& out, const LinkedList& list) {
    Node *cur = list.head;
    while (cur != NULL) {
        out << cur->getData();
        cur = cur->getNext();
    }
    return out;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论