如何为 Stack 对象制作复制功能?

How to make a copy function for a Stack object?

提问人:Daniel Dinosaur 提问时间:10/7/2021 最后编辑:Ken WhiteDaniel Dinosaur 更新时间:10/7/2021 访问量:497

问:

我正在尝试使用模板编写一个表示 C++ 中 Stack 对象的类。此堆栈对象将保存为数据“EToll”对象,这些对象表示现实世界中的汽车。

这是一项大学任务,对我施加了一些限制。它们如下:

堆栈必须

  1. 通过围绕 LinkedList 进行“包装”来构建(本质上,我只是包含一个“LinkedList”作为堆栈的私有成员,并基于我编写的 LinkedList 类中的函数构建了它的函数)。
  2. 从堆栈中打印或删除元素必须通过堆栈中的方法(例如 push()、pop() 等)完成,并且不能只从 LinkedList 中调用 print 或删除方法。

堆栈不能

  1. 使用关键字“struct”或“friend”
  2. 揭示内部结构(例如通过公开返回“数据”)

说完这些,让我解释一下我想做什么。我想通过重载流插入运算符(即“<<”)来输出堆栈对象的全部内容。我知道堆栈的构建方式使这相当不方便,但这是任务的要求之一。这是我的“<<”运算符重载代码:

template <typename T>
ostream& operator << (ostream& out, LStack<T>& LS)
{
  if (LS.isEmpty())
  {
    out << "List is empty.";
  } else
  {
    LStack<T> LScopy;
    LScopy = LS.copy(LS); //ensures original input LS remains unmodified

    while (!(LScopy.isEmpty()))
    {
      out << "(";
      out << LScopy.peek().get_licence();
      out << ", ";
      out << LScopy.peek().get_charge();
      out << ") ";
      LScopy.pop(); //continues the traversal of LScopy
    }

    //delete LS copy here to prevent memory leak

    return out;
  }
}

我需要一个复制函数来确保输入“LS”不会在“<<”重载中被修改。我几乎没有使用复制功能或模板的经验,所以我不知道如何制作我的复制功能。其他试图实现类似事情的线程(例如 C++ 为堆栈类创建复制构造函数)没有工作。Memcpy也没有奏效。这是我尝试使用我的复制功能执行的操作:

//returns a copy of parameter 'src' as a LinkedList<T>&
template <typename T>
LStack<T>& LStack<T>::copy(LStack<T>& src)
{
  LStack<T>* srcCopy = new LStack<T>();

  //copying contents of src to srcCopy
  memcpy(srcCopy, src, sizeof(src));

  //returning the copied LStack
  return srcCopy;
}

这是我的堆栈类的基本代码(为了简洁起见,没有包含完整的内容):

//start macroguard
#ifndef LSTACK_H
#define LSTACK_H

#include "LinkedList.h"
#include <x> <y> <z> etc ...

template <typename T>
class LStack 
{
public: 
  //constructor:
  LStack();

  //Destructor:
  ~LStack();

  //push - adds item to top of stack
  void push(T& obj);

  //copy function - not working at present
  LStack<T>& copy(LStack<T>& src);

  //pop - removes and returns item at top of Stack. If
  //stack is empty, do nothing
  T pop();

  //peek - returns item at top of stack
  T& peek();

  //size - returns number of items in the stack
  int size() const;

  //isEmpty - indicates if the stack has 0 or >0 items
  bool isEmpty();

private: 
  LinkedList<T> data;
};

//'<<' operator overload - prints all items in stack
template <typename T>
ostream& operator << (ostream&, LStack<T>& LS);

#include "LStack.hpp"
#endif //end of macroguard

以下是我的 LinkedList 类的基本代码:

//start macroguard
#ifndef LINKEDLIST_H
#define LINKEDLIST_H

#include "Node.h"
#include <x> <y> <z> etc...

template <typename T>
class LinkedList
{
public:

  //Constructor: 
  LinkedList();

  //Destructor:
  ~LinkedList();

  //addToHead - adds an item to head of list
  void addToHead(T& item);

  //addToTail - adds an item to tail of list
  void addToTail(T& item);

  //removeNode - calls relevant function if parameter 
  //'nodeToRemove' was head or tail. otherwise, removes 
  //an internal node from the list.
  void removeNode(Node<T>* nodeToRemove);

  //removeFromHead - removes an item from head of list
  void removeFromHead();

  //removeFromTail - removes an item from tail of list
  void removeFromTail();

  //length - returns number of Nodes in list
  int length();

  //isEmpty - indicates whether list has 0 or >0 items
  bool isEmpty();

  //getHead - returns 'data' value of list's head
  T& getHead();

  //getTail - returns 'data' value of list's tail
  T& getTail();

  //getCurrentData - returns 'data' value of list's 
  //'current' pointer
  T& getCurrentData();

  //moveCurrentForward - moves 'current' pointer to 
  //next node
  void moveCurrentForward();

  //moveCurrentBackward - moves 'current' pointer to 
  //previous node
  void moveCurrentBackward();

  //moveCurrentToHead - moves 'current' pointer to 
  //list's head
  void moveCurrentToHead();

  //moveCurrentToTail - moves 'current' pointer to 
  //list's tail
  void moveCurrentToTail();

private:
  Node<T>* head;
  Node<T>* tail;
  Node<T>* current; //used when traversing list

};

template <typename T>
ostream& operator << (ostream& out, LinkedList<T>& LL);

#include "LinkedList.hpp"
#endif //end of macroguard

最后是我的 Node 类的基本代码:

#ifndef NODE_H
#define NODE_H
#include "EToll.h"
#include <x> <y> <z> etc....

template <typename T>
class Node 
{

public: 
  //Constructors
  Node(); //default

  //i = data item, n = next, p = prev
  Node(const T& i, Node* n, Node* p); //detailed constructor

  //destructor
  ~Node();

  //set_next - sets the next value of Node
  void set_next(Node* next_ptr);

  //set_prev - same as above

  //set_data - sets the data value of Node
  void set_data(const T& new_data);

  //get_next - returns the next value of Node


  //get_prev - same as above

  //get_data - returns the data value of Node
  T& get_data();

private: 
  Node* next;
  Node* prev;
  T data;

};

#include "Node.hpp"
#endif

最后的笔记:

  1. 请原谅任何明显的问题,例如内存泄漏或未优化的编程决策。我是数据结构的新手。另外,我是C++的新手 - 我来自Java,一切都简单得多。我现在的目标是“确保一切正常,稍后再解决问题”。
  2. 如果你需要任何额外的代码或解释为什么我做了某些事情,请询问,我会提供给你。

非常感谢您的帮助。

C++ 链表 堆栈 构造函数 doublebly-linked-list

评论

0赞 tttony 10/7/2021
你应该添加 C++ 标签
0赞 user207421 10/7/2021
XY 问题。您无需复制堆栈即可输出它。再想一想。
0赞 Martin York 10/7/2021
您可以查看一些人们实现链表的代码审查示例: codereview.stackexchange.com/q/125955/507
0赞 user4581301 10/7/2021
以上是100%正确的。但这个问题的现状给了我一个机会,让我继续咆哮三则。不要编写复制函数。执行C++操作并编写适当的复制构造函数和赋值运算符。如果需要的话。如果你不这样做,那就接受零法则。一般的经验法则是尽可能接近需要保护的资源使用三或五规则,并对构建在该资源包装器之上的所有内容使用零法则。
1赞 JaMiT 10/7/2021
“我需要一个复制功能来确保输入'LS'不会在'<<'重载中被修改。”-- 如果要确保不对其进行修改,则应引用。所以现在我想知道 -- 谁决定了签名?如果它是给你的,它可能是为了恢复到原来的状态,而不是不修改。(我想到的不是最好的方法,但话又说回来,不利用基础链表也不一定是最好的方法。不过,它可能有一个教育目标。因此,我问。LSconstoperator<<LS

答: 暂无答案