你能从另一种方法调用复制构造函数吗?

时间:2010-01-09 07:06:13

标签: c++ copy-constructor

/** @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 个答案:

答案 0 :(得分:4)

如果我理解你的问题,你就无法做你想做的事。

在对象上调用任何其他方法之前,必须完全构造对象(这里有一个例外,我会回过头来看)。此外,一个对象只能构造一次(*)。因此,当您可以调用复制方法时,该对象已经构建,您不能(也不应该)第二次构造它。

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

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

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

这会生成aList的副本,然后使用此副本交换对象的当前内容。现在具有列表内容的副本将在复制返回时被正确销毁。

最后,如果您打算这样做,目前的建议实际上是调整一下并以这种方式写下来:

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

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

* - 您可以做奇怪的事情并使用placement new构建一个对象两次。但没有充分的理由这样做以及为什么不这样做的原因很多。

答案 1 :(得分: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);

我发现后者很尴尬。但是,如果要获取指向成员函数的指针,则可能需要明确地按名称引用运算符。

答案 2 :(得分:1)

问题是,如果这样的语法如此简单,那么为什么要使用copy方法:&gt; (除非你是那些希望明确说明副本的防守人员之一 - 然后我提交,我也是其中之一)。

您可能也有兴趣复制(分配)运算符

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

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

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

答案 3 :(得分:1)

构造函数很特殊,因为当对象未初始化时,它们仅被称为 。因此,您不能将任何简单函数,副本或其他方式调用。 C ++需要这样做,因为它有助于编写代码,当您添加功能时,代码会减少。

您可能希望将复制构造函数的主体移至Copy()并从Copy()调用List::List(List const&)