2
/** @file ListP.cpp
 *  ADT list - Pointer-based implementation. */

#include <iostream>
#include <cstddef>  // for NULL
#include <new>   // for bad_alloc
#include "ListP.h"  // header file

using namespace std;

List::List() : size(0), head(NULL)
{
} // end default constructor

List::List(const List& aList) : size(aList.size)
{
 if (aList.head == NULL)
  head = NULL; // original list is empty

 else
 { // copy first node
  head = new ListNode;
  head->item = aList.head->item;

  // copy rest of list
  ListNode *newPtr = head; // new pointer
  // newPtr points to last node in new list
  // origPtr points to nodes in original list
  for (ListNode *origPtr = aList.head->next; origPtr != NULL; origPtr = origPtr->next)
  { 
   newPtr->next = new ListNode;
   newPtr = newPtr->next;
   newPtr->item = origPtr->item;
  } // end for

  newPtr->next = NULL;
 } // end if
} // end copy constructor

void List::copy(const List& aList)
{
 List::List(aList);
} // end copy

我正在尝试创建一个名为 copy 的方法,它只调用复制构造函数。当我在 main 中测试此方法时,目标列表仍然为空。我已经逐步完成并执行了所有正确的行,但是当复制构造函数返回时,似乎什么都没有保存。我觉得这与范围有关,但无法确定问题所在。这是驱动程序:

#include <iostream>
using namespace std;

#include "ListP.h" 

int main ()
{
 List aList;

 ListItemType dataItem;
 aList.insert(1, 9);    
 aList.insert(2, 4); 
 aList.insert(3, 1); 
 aList.insert(4, 2); 

 List bList;
 bList.copy(aList);

 bList.retrieve(1, dataItem);
 cout << dataItem << endl;
 cout << bList.getLength() << endl;

 return 0;
}
4

4 回答 4

4

如果我理解你的问题,你就不能做你想做的事。

在您可以对对象调用任何其他方法之前,必须完全构造该对象(这里有一个例外,我会回到那个)。此外,一个对象只能构造一次 (*)。因此,当您可以调用您的复制方法时,该对象已经被构造并且您不能(也不应该)再次构造它。

不能在未完全构造的对象上调用方法的一个例外(即构造函数尚未返回)是构造函数本身可以在部分构造的对象上调用方法。因此,您可以从复制构造函数中调用复制方法,反之则不行。

也就是说,如果您的对象提供了优化的交换功能,那么可能会考虑一个标准技巧:

void List::copy(const List& aList)
{
    List acopy(aList);
    swap(*this, acopy);
}

这会创建 aList 的副本,然后将对象的当前内容与此副本交换。当 copy 返回时,现在具有您列表内容的 acopy 将被正确破坏。

最后,如果你打算这样做,目前的建议实际上是稍微调整一下,然后这样写:

void List::copy(List aList)
{
    swap(*this, aList);
}

在某些情况下,这可能更有效(并且永远不会降低效率)。

* - 你可以做一些奇怪的事情,并用新的位置构造一个对象两次。但是没有充分的理由这样做,并且有很多理由不这样做。

于 2010-01-09T07:56:24.153 回答
2

在您的驱动程序中,您有

List bList;
bList.copy(aList);

相反,调用复制构造函数

List bList(aList);

或者

List bList = aList;

…查看您的“复制”方法:构造函数创建一个新实例。您的 List::copy 方法调用复制构造函数,在堆栈上创建 List 的新实例。然后它返回,你的新实例消失了。

您可能想要的而不是“复制”方法是定义一个赋值运算符,

List& List::operator=(const List& aList)
{
   if (this != &aList)
   {
      // Do your copying here
   }

   return *this;
}

然后你的司机可以说

List bList;
// ...Presumably manipulate bList in some other ways in-between...
bList = aList;

要从同一类的另一个方法中调用赋值运算符,例如

*this = aList;

或者

operator=(aList);

我觉得后者很尴尬。但是,如果您想获得指向成员函数的指针,则可能需要通过名称显式引用运算符。

于 2010-01-09T07:19:08.910 回答
2

构造函数是特殊的,因为它们在对象未初始化时才被调用。因此,您不能调用任何简单的函数、复制或其他方式。C++ 需要这个,因为它有助于编写在添加功能时更少中断的代码。

可能您想要的是将复制构造函数的主体移动到Copy()并调用Copy()from List::List(List const&)

于 2010-01-09T07:59:03.560 回答
1

问题是,如果这样的语法如此简单,那么为什么要制作一个copy方法:>(除非您是那些想要明确说明副本的防御者之一——然后我提交,我也是其中之一)。

您可能还对做一个复制(赋值)运算符感兴趣:

List& List::operator=(const List& aList)
{
    //
}

至于无法调用复制构造函数,请参阅C++ FAQ Lite on Constructors。这个帖子也问了同样的问题。

无法从类中显式调用构造函数是 C++ 标准文档的一部分,但是 maaan,你不想读那个东西……但是 ;-)

于 2010-01-09T07:12:07.727 回答