【问题标题】:no suitable conversion function from "const DListNode" to "DListNode *" exists for doubly linked list copy constructor对于双向链表复制构造函数,不存在从“const DListNode”到“DListNode *”的合适转换函数
【发布时间】:2016-10-04 20:35:32
【问题描述】:

我目前正在为双向链表类编写复制构造函数/赋值运算符,但遇到了问题。

双链表.h

#include <cstdlib>
#include <iostream>
using namespace std;
class DoublyLinkedList; // class declaration

// list node
class DListNode {
private: int obj;
  DListNode *prev, *next;
  friend class DoublyLinkedList;
public:
  DListNode(int e=0, DListNode *p = NULL, DListNode *n = NULL)
    : obj(e), prev(p), next(n) {}
  int getElem() const { return obj; }
  DListNode * getNext() const { return next; }
  DListNode * getPrev() const { return prev; }
};

// doubly linked list
class DoublyLinkedList {
protected: DListNode header, trailer;
public:
  DoublyLinkedList() : header(0), trailer(0) // constructor
  { header.next = &trailer; trailer.prev = &header; }
  DoublyLinkedList(const DoublyLinkedList& dll); // copy constructor
  ~DoublyLinkedList(); // destructor
  DoublyLinkedList& operator=(const DoublyLinkedList& dll); // assignment operator
  // return the pointer to the first node
  DListNode *getFirst() const { return header.next; } 
  // return the pointer to the trailer
  const DListNode *getAfterLast() const { return &trailer; }
  // return if the list is empty
  bool isEmpty() const { return header.next == &trailer; }
  int first() const; // return the first object
  int last() const; // return the last object
  void insertFirst(int newobj); // insert to the first of the list
  int removeFirst(); // remove the first node
  void insertLast(int newobj); // insert to the last of the list
  int removeLast(); // remove the last node
};
// output operator
ostream& operator<<(ostream& out, const DoublyLinkedList& dll);

这是一个补充头文件,其中同时声明了节点和链表类。我注意到 DoublyLinkedList 的受保护类成员(标头和尾标)不是 DListNode 指针,而是实际的 DListNode 值;稍后会详细介绍。

我在 DoublyLinkedList.cpp 中的复制构造函数

DoublyLinkedList::DoublyLinkedList(const DoublyLinkedList& dll)
{
  // Initialize the list
  header.next = &trailer; trailer.prev = &header;
  DListNode* iter = dll.header; // PROBLEM LINE
  if (this != &dll) {
      while (iter != nullptr) {
          insertLast(iter->obj);
          iter = iter->next;
      }
  }
}

我尝试了很多不同的方法来解决这个问题,无论是否编辑头文件。我无法将 header 和 trailer 更改为 DListNode*,因为它们不允许更改,并且将 iter 更改为非指针意味着我无法遍历链表;所以我现在陷入了僵局。因为我无法更改操作数的数据类型,所以我不确定如何修复该错误。我认为这可能与作为常量引用传递的 dll 有关,但即使摆弄它也没有多大作用。我已经看了几个小时了,但似乎无法让它工作。提前感谢您的帮助!

【问题讨论】:

  • 'DListNode const* iter = &dll.header;'怎么样

标签: c++ linked-list copy-constructor doubly-linked-list


【解决方案1】:

您的列表有两个单元格需要管理,即使它是空的。 您可以采用不同的设计选择

class DoublyLinkedList {
protected:
  DListNode *header;
public:
  DoublyLinkedList() : header(nullptr) {} // constructor
  ...
  bool isEmpty() const { return header == nullptr; }
  void insertLast(int val)
     {  if (header == nullptr) {
            header = new DListNode(val);
            header->next = header->prev = header;
        }
        else {
            header->prev->next = new DListNode(val, header->prev, header);
            header->prev = header->prev->next;
        }
     }
};

不过,根据您的设计选择(开头一个空单元格,最后一个空单元格),您可以将复制构造函数定义为

DoublyLinkedList::DoublyLinkedList(const DoublyLinkedList& dll)
{
  // Initialize the list
  header.next = &trailer; trailer.prev = &header;
  if (this != &dll) {
      DListNode* iter = dll.header.next;
      while (iter != &dll.trailer) { // no insertion if dll is empty
          insertLast(iter->obj);
          iter = iter->next;
      }
  }
}

您应该在每次操作之前和之后绘制数据结构,以确保您的算法是如何工作的。

您还可以实现一个不变量(方法bool isValid() const)来验证单元格之间的链接:cell-&gt;next-&gt;prev 应该是cell,除了最后一个空节点,cell-&gt;prev-&gt;next 应该是cell,除了第一个空节点节点。

【讨论】:

  • 啊,我明白了。在我的编程入门课程中,我的教授教授链表作为标题和尾部分别指向列表的第一个和最后一个节点,我错误地认为它在这里。谢谢!
【解决方案2】:

这个列表看起来与通常的双向链表实现有点不同,但它可以工作。

从您显示的代码看来,两个非指针成员 headertrailer 仅用于跟踪列表的两端,但实际上并不是列表的一部分。上面代码片段中的一些内容支持这一点:

  • 一个空列表有 headertrailer 相互指向,没有为这两个节点设置值,它们之间也没有其他节点
  • getFirst(),根据上面的评论,它应该返回一个指向第一个节点的指针,实际上返回header之后的节点而不是header本身
  • 您有一个getAfterLast() 函数,根据它的名称判断,它应该在列表中最后一个节点之后返回一个标记,并返回trailer

如果以上是正确的并且headertrailer 实际上不是列表的一部分,那么你的复制构造函数的实现是错误的。它应该只从输入列表中复制实际值节点,不包括标题和尾部。这意味着您从以getFirst() 开始的节点复制节点值,并在到达getAfterLast() 时停止。

代码中有这样的东西:

if (this != &dll) {
    const DListNode* iter = dll.getFirst();
    while (iter != dll.getAfterLast()) {
        insertLast(iter->obj);
        iter = iter->next;
    }
}

请注意,这也可以很好地处理源列表为空的情况。如果dll 为空,dll.getFirst() 实际上会返回预告片,这也是getAfterLast() 返回的内容。所以while循环不会被执行,列表会保持为空。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    相关资源
    最近更新 更多