在C++98中,关于链表类的非成员重载运算符<<的问题。

huangapple go评论85阅读模式
英文:

Question on overload non-member operator << in a linkedlist class in c++98

问题

Sure, here's the translated code you provided:

  1. 有人可以帮我解答这个问题吗?为了提供背景信息,我有三个类,`Account.h` `Account.cpp``Node.h` `Node.cpp``LinkedList.h` `Linkedlist.cpp`,以及包含 `int main()` `demo.cpp`。所有当前的函数都能正常工作,只有打印出链表的功能还没实现,这也是我的问题所在。
  2. 问题明确要求:
  3. &gt; 实现一个非成员重载的 `operator &lt;&lt;` 函数,使用 `Account` 中的 `operator &lt;&lt;`,允许你执行如下操作:
  4. &gt; `cout &lt;&lt; MyLinkedList &lt;&lt; endl;`
  5. 我从 `LinkedList.cpp` `Account.cpp` 中复制了与这个问题相关的特定部分,因为如果我把所有代码都粘贴在这里,会太长了。
  6. `LinkedList.cpp` 中,有一个未能正常工作的重载的 `operator &lt;&lt;` 函数,代码如下所示:请注意 `value_type` `Account` typedef
  7. ```c++
  8. #include &quot;LinkedList.h&quot;
  9. LinkedList::value_type LinkedList::getCurrent() const {
  10. if (current != NULL) {
  11. return current-&gt;getData();
  12. } else {
  13. return value_type();
  14. }
  15. }
  16. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list) { // not working, compile error!
  17. value_type current = getCurrent();
  18. while (current != NULL) {
  19. out &lt;&lt; &quot;(&quot; &lt;&lt; acc.getName() &lt;&lt; &quot;,&quot; &lt;&lt; acc.balance() &lt;&lt; &quot;)&quot; &lt;&lt; endl;
  20. }
  21. return out;
  22. }

Account.cpp 中的代码如下:

  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, const Account&amp; acc)
  2. {
  3. out &lt;&lt; &quot;(&quot; &lt;&lt; acc.getName() &lt;&lt; &quot;,&quot; &lt;&lt; acc.balance() &lt;&lt; &quot;)&quot; &lt;&lt; endl;
  4. return out;
  5. }

这些是我的 node.h 文件的类声明:

  1. #ifndef TEKAAI_NODE
  2. #define TEKAAI_NODE
  3. #include &quot;Account.h&quot;
  4. class Node
  5. {
  6. public:
  7. // 外部可见的成员
  8. // 以下是成员函数
  9. // 使用 typedef 将 value_type 指定为 Account
  10. typedef Account value_type;
  11. // 默认构造函数
  12. Node();
  13. // 参数构造函数
  14. Node(const value_type&amp; initial_data, Node* initial_link);
  15. ~Node(); // 析构函数
  16. void setNext(Node* n);
  17. void setPrevious(Node* p);
  18. Node* getNext() const;
  19. Node* getPrevious() const;
  20. // 数据的获取和设置
  21. // 前提条件:Current 已初始化
  22. // 后置条件:设置数据
  23. void setData(const value_type&amp; i);
  24. // 前提条件:数据已初始化
  25. // 后置条件:返回存储的数据
  26. value_type getData() const;
  27. private:
  28. value_type data; // 节点保存的数据
  29. Node* next; // 指向下一个节点的指针
  30. Node* previous; // 指向前一个节点的指针
  31. };
  32. #endif

这些是我的 LinkedList.h 文件中的类声明:

  1. #ifndef TEKAAI_LINKEDLIST_H
  2. #define TEKAAI_LINKEDLIST_H
  3. #include &quot;Account.h&quot;
  4. #include &quot;Node.h&quot;
  5. #include &lt;iostream&gt;
  6. class LinkedList
  7. {
  8. public:
  9. typedef Account value_type;
  10. // 外部可见的成员
  11. // 这些是成员函数
  12. // 构造函数
  13. LinkedList();
  14. // 析构函数
  15. ~LinkedList();
  16. void addToHead(const value_type&amp; account);
  17. void addToTail(const value_type&amp; account);
  18. void addCurrent(const value_type&amp; account);
  19. value_type removeFromHead();
  20. value_type removeFromTail();
  21. value_type removeFromCurrent();
  22. // 前提条件:链表包含节点
  23. // 后置条件:将当前节点移到头部
  24. void start();
  25. // 前提条件:链表包含节点
  26. // 后置条件:将当前节点移到尾部
  27. void end();
  28. // 前提条件:链表包含节点
  29. // 后置条件:将当前节点向右移动一个节点
  30. void forward();
  31. // 前提条件:链表包含节点
  32. // 后置条件:将当前节点向左移动一个节点
  33. void back();
  34. // 前提条件:链表包含节点
  35. // 后置条件:返回当前节点存储的数据帐户的值
  36. value_type getCurrent() const;
  37. // 前提条件:链表已初始化,包含节点
  38. // 后置条件:返回链表的长度
  39. int length();
  40. private:
  41. Node* head;
  42. Node* tail;
  43. Node* current;
  44. };
  45. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list);
  46. #endif

正如你在上面的 LinkedList 类声明中看到的,我必须使用其中一个上面的函数之一来尝试打印我的链表。我想听听你的意见,是否可能使用上述 Account 中的重载 << 操作符以及其中一个函数来打印我的链表,正如问题所指定的那样。

谢谢。

另外请注意:只是想让你知道,我可以使用函数 Node* getHead() const; 打印我的链表,该函数返回头部,但我只是想知道是否可以在不使用 getHead() 函数的情况下打印链表。我想我们的讲师只是在玩弄我们,试图通过他的实验活动让我们失去理智。

  1. <details>
  2. <summary>英文:</summary>
  3. 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.
  4. The question specifically says:
  5. &gt; Implement a non-member overloaded `operator &lt;&lt;` function, that uses the `operator &lt;&lt;` from `Account`, to allow you to perform an operation like:
  6. &gt;
  7. &gt; `cout &lt;&lt; MyLinkedList &lt;&lt; endl;`
  8. 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.
  9. Code from `LinkedList.cpp` with overloaded `operator &lt;&lt;` function &quot;not yet working&quot; is as shown below: Please note `value_type` is typedef for `Account`.
  10. ```c++
  11. #include &quot;LinkedList.h&quot;
  12. LinkedList::value_type LinkedList::getCurrent() const {
  13. if (current != NULL) {
  14. return current-&gt;getData();
  15. } else {
  16. return value_type();
  17. }
  18. }
  19. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list) { // not working, compile error!
  20. value_type current = getCurrent();
  21. while (current != NULL) {
  22. out &lt;&lt; &quot;(&quot; &lt;&lt; acc.getName() &lt;&lt; &quot;,&quot; &lt;&lt; acc.balance() &lt;&lt; &quot;)&quot; &lt;&lt; endl;
  23. }
  24. return out;
  25. }

Code from Account.cpp is as shown below:

  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, const Account&amp; acc)
  2. {
  3. out &lt;&lt; &quot;(&quot; &lt;&lt; acc.getName() &lt;&lt; &quot;,&quot; &lt;&lt; acc.balance() &lt;&lt; &quot;)&quot; &lt;&lt; endl;
  4. return out;
  5. }

These are the class declarations for my node.h file:

  1. #ifndef TEKAAI_NODE
  2. #define TEKAAI_NODE
  3. #include &quot;Account.h&quot;
  4. class Node
  5. {
  6. public:
  7. // members that are externally visible
  8. // Below are Member functions
  9. // specifying value_type to Account using typedef
  10. typedef Account value_type;
  11. // Default constructor
  12. Node();
  13. // Parameter Constructors
  14. Node(const value_type&amp; initial_data, Node* initial_link);
  15. ~Node(); //destructor
  16. void setNext(Node* n);
  17. void setPrevious(Node* p);
  18. Node* getNext() const;
  19. Node* getPrevious() const;
  20. // the data getters and setters
  21. // Pre-condition: Current has been initialized
  22. // Post-condition: set data
  23. void setData(const value_type&amp; i);
  24. // Pre-condition: Data has been initialized
  25. // Post-condition: returns stored data
  26. value_type getData() const;
  27. private:
  28. value_type data; //the data held by the node
  29. Node* next; //a pointer to the next node
  30. Node* previous; //a pointer to the previous node
  31. };
  32. #endif

These are the class declarations in my LinkedList.h file:

  1. #ifndef TEKAAI_LINKEDLIST_H
  2. #define TEKAAI_LINKEDLIST_H
  3. #include &quot;Account.h&quot;
  4. #include &quot;Node.h&quot;
  5. #include &lt;iostream&gt;
  6. class LinkedList
  7. {
  8. public:
  9. typedef Account value_type;
  10. // Members that are externally visible
  11. // These are Member functions
  12. // Constructors
  13. LinkedList();
  14. // Destructor
  15. ~LinkedList();
  16. void addToHead(const value_type&amp; account);
  17. void addToTail(const value_type&amp; account);
  18. void addCurrent(const value_type&amp; account);
  19. value_type removeFromHead();
  20. value_type removeFromTail();
  21. value_type removeFromCurrent();
  22. // Pre-condition: LinkedList contains nodes
  23. // Post-condition: moves current to the head
  24. void start();
  25. // Pre-condition: LinkedList contains nodes
  26. // Post-condition: moves current to the tail
  27. void end();
  28. // Pre-condition: LinkedList contains nodes
  29. // Post-condition: moves current one node to the right
  30. void forward();
  31. // Pre-condition: LinkedList contains nodes
  32. // Post-condition: moves current one node to the left
  33. void back();
  34. // Pre-condition: LinkedList contains nodes
  35. // Post-condition: returns the value of data account stored
  36. // in current node
  37. value_type getCurrent() const;
  38. // Pre-condition: LinkedList is initialized, containing
  39. // nodes
  40. // Post-condition: returns the length of the list
  41. int length();
  42. private:
  43. Node* head;
  44. Node* tail;
  45. Node* current;
  46. };
  47. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list);
  48. #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:

  1. ostream& operator << (ostream& out, const Account& acc)
  2. 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):

  1. ostream& operator << (ostream& out, const LinkedList& list) {
  2. LinkedList::Node *cur = list.getFirst();
  3. while (cur != NULL) {
  4. out << cur->getData();
  5. cur = cur->getNext();
  6. }
  7. return out;
  8. }

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:
  1. class LinkedList
  2. {
  3. public:
  4. ...
  5. bool hasCurrent() const;
  6. value_type getCurrent() const;
  7. ...
  8. };
  1. bool LinkedList::hasCurrent() const {
  2. return (current != NULL);
  3. }
  4. LinkedList::value_type LinkedList::getCurrent() const {
  5. return current->getData();
  6. }
  1. ostream& operator << (ostream& out, LinkedList& list) {
  2. list.start();
  3. while (list.hasCurrent()) {
  4. out << list.getCurrent();
  5. list.forward();
  6. }
  7. return out;
  8. }
  • change your getCurrent() method to return the Account object by pointer instead of by value so that it can return a NULL pointer when the iteration is at the end of the list:
  1. class Node
  2. {
  3. public:
  4. ...
  5. value_type& getData();
  6. ...
  7. };
  1. LinkedList::value_type* LinkedList::getCurrent() {
  2. if (current != NULL) {
  3. return &(current->getData());
  4. } else {
  5. return NULL;
  6. }
  7. }
  1. ostream& operator << (ostream& out, LinkedList& list) {
  2. Account *cur;
  3. list.start();
  4. while ((cur = list.getCurrent()) != NULL) {
  5. out << *cur;
  6. list.forward();
  7. }
  8. return out;
  9. }
  • make the LinkedList operator be a friend of the LinkedList class so it can access the private head member directly:
  1. class LinkedList
  2. {
  3. public:
  4. ...
  5. friend ostream& operator << (ostream& out, const LinkedList& list);
  6. ...
  7. private:
  8. Node* head;
  9. ...
  10. };
  11. ostream& operator << (ostream& out, const LinkedList& list);
  1. ostream& operator << (ostream& out, const LinkedList& list) {
  2. Node *cur = list.head;
  3. while (cur != NULL) {
  4. out << cur->getData();
  5. cur = cur->getNext();
  6. }
  7. return out;
  8. }
英文:

First, your operator&lt;&lt;'s should be taking their 2nd parameters by const reference, not by value, eg:

  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, const Account&amp; acc)
  2. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; 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):

  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list) {
  2. LinkedList::Node *cur = list.getFirst();
  3. while (cur != NULL) {
  4. out &lt;&lt; cur-&gt;getData();
  5. cur = cur-&gt;getNext();
  6. }
  7. return out;
  8. }

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:
  1. class LinkedList
  2. {
  3. public:
  4. ...
  5. bool hasCurrent() const;
  6. value_type getCurrent() const;
  7. ...
  8. };
  1. bool LinkedList::hasCurrent() const {
  2. return (current != NULL);
  3. }
  4. LinkedList::value_type LinkedList::getCurrent() const {
  5. return current-&gt;getData();
  6. }
  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, LinkedList&amp; list) {
  2. list.start();
  3. while (list.hasCurrent()) {
  4. out &lt;&lt; list.getCurrent();
  5. list.forward();
  6. }
  7. return out;
  8. }
  • change your getCurrent() method to return the Account object by pointer instead of by value so that it can return a NULL pointer when the iteration is at the end of the list:
  1. class Node
  2. {
  3. public:
  4. ...
  5. value_type&amp; getData();
  6. ...
  7. };
  1. LinkedList::value_type* LinkedList::getCurrent() {
  2. if (current != NULL) {
  3. return &amp;(current-&gt;getData());
  4. } else {
  5. return NULL;
  6. }
  7. }
  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, LinkedList&amp; list) {
  2. Account *cur;
  3. list.start();
  4. while ((cur = list.getCurrent()) != NULL) {
  5. out &lt;&lt; *cur;
  6. list.forward();
  7. }
  8. return out;
  9. }
  • make the LinkedList operator be a friend of the LinkedList class so it can access the private head member directly:
  1. class LinkedList
  2. {
  3. public:
  4. ...
  5. friend ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list);
  6. ...
  7. private:
  8. Node* head;
  9. ...
  10. };
  11. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list);
  1. ostream&amp; operator &lt;&lt; (ostream&amp; out, const LinkedList&amp; list) {
  2. Node *cur = list.head;
  3. while (cur != NULL) {
  4. out &lt;&lt; cur-&gt;getData();
  5. cur = cur-&gt;getNext();
  6. }
  7. return out;
  8. }

huangapple
  • 本文由 发表于 2023年4月19日 15:04:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76051604.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定