Compartilhar via


Operadores de construtores de cópia e de atribuição de cópia (C++)

Observação

A partir do C++11, há suporte para dois tipos de atribuição no idioma: atribuição de cópia e atribuição de movimentação. Neste artigo, "atribuição" significa atribuição de cópia, a menos que explicitamente declarado o contrário. Para obter informações sobre a atribuição de movimentação, consulte Mover construtores e mover operadores de atribuição (C++).

Tanto a operação de atribuição como a operação de inicialização fazem com que os objetos sejam copiados.

  • Atribuição: quando o valor de um objeto é atribuído a outro objeto, o primeiro objeto é copiado para o segundo objeto. Portanto, esse código copia o valor de b em a:

    Point a, b;
    ...
    a = b;
    
  • Inicialização: a inicialização ocorre quando você declara um novo objeto, ao passar argumentos de função por valor ou quando você retorna por valor de uma função.

Você pode definir a semântica de “cópia” para objetos do tipo classe. Por exemplo, considere este código:

TextFile a, b;
a.Open( "FILE1.DAT" );
b.Open( "FILE2.DAT" );
b = a;

O código anterior poderia significar "copiar o conteúdo de FILE1.DAT para FILE2.DAT" ou "ignore FILE2.DAT e faça de b um segundo manipulador para FILE1.DAT". Você deve anexar a semântica de cópia apropriada a cada classe, como segue:

  • Use um operador operator= de atribuição que retorna uma referência ao tipo de classe e usa um parâmetro que é passado por const referência, por exemplo ClassName& operator=(const ClassName& x);.

  • Use o construtor de cópia.

Se você não declarar um construtor de cópia, o compilador gerará um construtor de cópia em termos de membro para você. Da mesma forma, se você não declarar um operador de atribuição de cópia, o compilador gerará um operador de atribuição de cópia em termos de membro para você. A declaração de um construtor de cópia não suprime o operador de atribuição de cópia gerado pelo compilador, e vice-versa. Se você implementar qualquer um, recomendamos que implemente o outro também. Ao implementar ambos, o significado do código é claro.

O construtor de cópia usa um argumento do tipo ClassName&, onde ClassName é o nome da classe. Por exemplo:

// spec1_copying_class_objects.cpp
class Window
{
public:
    Window( const Window& );            // Declare copy constructor.
    Window& operator=(const Window& x); // Declare copy assignment.
    // ...
};

int main()
{
}

Observação

Faça com que o tipo do argumento do construtor de cópia seja const ClassName& sempre que possível. Isso evita que o construtor de cópia altere acidentalmente o objeto copiado. Ele também permite que você copie de objetos const.

Construtores de cópia gerados pelo compilador

Os construtores de cópia gerados pelo compilador, como os construtores de cópia definidos pelo usuário, têm um único argumento do tipo "referência ao nome da classe". Uma exceção é quando todas as classes base e classes de membro têm construtores de cópia declarados como tendo um único argumento de tipo constclass-name&. Nesse caso, o argumento do construtor de cópia gerado pelo compilador também é const.

Quando o tipo de argumento para o construtor de cópia não é const, a inicialização por meio da cópia de um objeto const gera um erro. O inverso não é verdadeiro: se o argumento for const, você pode inicializar copiando um objeto que não seja const.

Os operadores de atribuição compiler-generated seguem o mesmo padrão para const. Eles tomam um único argumento do tipo ClassName&, a menos que os operadores de atribuição em todas as classes base e membros tomem argumentos do tipo const ClassName&. Nesse caso, o operador de atribuição gerado para a classe recebe um argumento const.

Observação

Quando classes básicas virtuais são inicializadas por construtores de cópia, sejam elas geradas pelo compilador ou definidas pelo usuário, elas são inicializadas somente uma vez: no ponto em que são construídas.

As implicações são semelhantes ao construtor de cópia. Quando o tipo de argumento não é const, a atribuição de um objeto const gera um erro. O inverso não é verdadeiro: se um valor const for atribuído a um valor que não seja const, a atribuição será bem-sucedida.

Para obter mais informações sobre operadores de atribuição sobrecarregados, consulte Atribuição.