Pergunta

/** @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

Eu estou tentando criar um método chamado copiar que simplesmente chama o construtor de cópia. Quando eu testar este método em main na lista de destino ainda permanece vazio. Tenho passou por ela e todas as linhas direitas são executadas, mas quando o construtor de cópia retorna nada parece ser salvo. Eu sinto isso tem algo a ver com escopo, mas não pode identificar o problema. Aqui está o programa do controlador:

#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;
}
Foi útil?

Solução

Se entendi sua pergunta, você não pode fazer o que você está tentando fazer.

Antes de chamar quaisquer outros métodos em um objeto, o objeto deve ser totalmente construído (há uma exceção aqui, eu vou voltar a isso). Além disso, um objecto apenas pode ser construída uma vez (*). Portanto, no momento em que você poderia chamar o seu método de cópia, o objeto já estaria construído e você não pode (e não deve) construí-la uma segunda vez.

A única excepção a não ser capaz de chamar um método de um objecto que não está totalmente construído (isto é, o construtor ainda não retornou) é que um construtor si pode chamar um método no objecto parcialmente construída. Então, você poderia chamar um método de cópia do construtor de cópia, mas não vice-versa.

Dito isso, se o seu objeto fornece uma função de troca otimizada, há um truque padrão que pode estar pensando em:

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

Isto faz uma cópia do aList e troca então o conteúdo atual do seu objeto com esta cópia. ACOPY que agora tem o conteúdo de sua lista antes serão devidamente destruídas quando copiar retornos.

Finalmente, se você estiver indo para fazê-lo, a recomendação atual é na verdade ajustá-lo um pouco e escrevê-lo desta maneira:

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

Sob certas circunstâncias, isso pode ser mais eficiente (e nunca é menos eficiente).

* - você pode fazer coisas estranhas e construir um objeto duas vezes com posicionamento novo. Mas não há nenhuma boa razão para fazer isso e muitas razões pelas quais não.

Outras dicas

Em seu programa de motorista, você tem

List bList;
bList.copy(aList);

Em vez disso, invocar o construtor de cópia com qualquer

List bList(aList);

ou

List bList = aList;

... Olhando para a sua "cópia" método: construtor Um cria uma nova instância. Seu método de Lista :: cópia chama o construtor de cópia, criar uma nova instância de lista na pilha. Em seguida, ele retorna, e sua nova instância é ido.

O que você provavelmente quer em vez de uma "cópia" método é definir um operador de atribuição,

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

   return *this;
}

Em seguida, o motorista poderia dizer

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

Para chamar o operador de atribuição de dentro de outro método da mesma classe, dizer

*this = aList;

ou

operator=(aList);

I encontrar o último estranho. Mas referindo-se a um operador explicitamente pelo nome pode ser necessário se você deseja obter um ponteiro para a função de membro.

Construtores são especiais porque eles são chamados de única quando o objeto é inicializado. Portanto, você não pode chamar qualquer como funções simples, copiar ou de outra forma. C ++ exige isso, porque ajuda a escrever código que quebra menos quando você adicionar recursos.

Provavelmente o que você quer é mover o corpo do construtor de cópia para Copy() e Copy() chamada de List::List(List const&).

A questão é, se essa sintaxe é tão fácil, então por que fazer um método copy em tudo:> (a menos que você é uma daquelas pessoas que querem defensivas das cópias explicitamente - então eu apresentar, eu sou um deles também).

Você pode também estar interessado em fazer uma cópia (atribuição) operador em vez disso:

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

Como para a incapacidade de chamar o construtor de cópia ver a C ++ FAQ Lite no Construtores . Este fio também faz a mesma pergunta.

A incapacidade de invocar construtores explicitamente de classe é uma parte do documento C ++ padrão, mas maaan, você não quer ler aquela coisa ... ainda; -)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top