Menu
Coddy logo textTech

Construtor de Cópia

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 20 de 104.

Um construtor de cópia cria um novo objeto como uma cópia de um objeto existente. Ele é chamado quando você inicializa um objeto a partir de outro objeto do mesmo tipo, passa um objeto por valor ou retorna um objeto por valor.

O construtor de cópia recebe uma referência const a um objeto da mesma classe:

class Player {
    std::string name;
    int health;
public:
    Player(std::string n, int h) : name(n), health(h) {}
    
    // Construtor de cópia
    Player(const Player& other) {
        name = other.name;
        health = other.health;
    }
};

Player original("Hero", 100);
Player copy = original;    // Construtor de cópia chamado
Player another(original);  // Também chama o construtor de cópia

Se você não definir um construtor de cópia, o compilador gera um que realiza uma cópia superficial - ele copia diretamente o valor de cada membro. Isso funciona bem para tipos simples, mas causa problemas quando sua classe gerencia memória dinâmica.

class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s) {
        data = new int[size];
    }
    
    // Construtor de cópia profunda
    Buffer(const Buffer& other) : size(other.size) {
        data = new int[size];              // Alocar nova memória
        for (size_t i = 0; i < size; i++)
            data[i] = other.data[i];       // Copiar conteúdos
    }
    
    ~Buffer() { delete[] data; }
};

Sem um construtor de cópia personalizado, ambos os objetos apontariam para a mesma memória. Quando um deles fosse destruído, o outro teria um ponteiro pendente. Uma cópia profunda aloca nova memória e copia os dados reais, garantindo que cada objeto possua seus próprios recursos.

challenge icon

Desafio

Fácil

Vamos criar um sistema de histórico de mensagens que demonstra a importância da cópia profunda quando sua classe gerencia memória dinâmica. Você criará uma classe MessageLog que armazena mensagens em um array alocado dinamicamente e implementará um construtor de cópia adequado para garantir que cada cópia tenha sua própria memória independente.

Você criará dois arquivos para organizar seu código:

  • MessageLog.h: defina uma classe MessageLog que gerencia uma coleção de mensagens usando memória dinâmica. Sua classe deve ter:
    • Membros privados: um ponteiro para um array de strings para armazenar mensagens, uma capacity para o número máximo de mensagens e uma count para o número atual de mensagens
    • Um construtor parametrizado que recebe uma capacidade, aloca o array no heap e inicializa count com 0
    • Um construtor de cópia que realiza uma cópia profunda: alocando nova memória e copiando todas as mensagens do objeto de origem
    • Um destrutor que libera a memória alocada e imprime "MessageLog destroyed"
    • Um método addMessage(string msg) que adiciona uma mensagem se houver espaço
    • Um método getCount() que retorna a quantidade atual de mensagens
    • Um método getMessage(int index) que retorna a mensagem no índice fornecido
  • main.cpp: demonstre que seu construtor de cópia cria uma cópia independente. Leia um valor de capacidade e duas mensagens da entrada e, então:
    • Crie um MessageLog chamado original com a capacidade informada
    • Adicione ambas as mensagens a original
    • Crie uma cópia chamada backup usando o construtor de cópia
    • Adicione uma terceira mensagem "New message" somente a original
    • Imprima "Original count: <count>"
    • Imprima "Backup count: <count>"
    • Imprima todas as mensagens de backup, uma por linha

O formato da entrada será:

  • Primeira linha: capacidade (inteiro)
  • Segunda linha: primeira mensagem (string)
  • Terceira linha: segunda mensagem (string)

Se sua cópia profunda for implementada corretamente, o backup deverá ter 2 mensagens, enquanto o original terá 3: provando que eles têm memória independente. Sem um construtor de cópia adequado, ambos compartilhariam o mesmo array e as alterações em um afetariam o outro!

Inclua seu arquivo de cabeçalho em main.cpp usando #include "MessageLog.h".

Experimente você mesmo

#include <iostream>
#include <string>
#include "MessageLog.h"
using namespace std;

int main() {
    // Ler entrada
    int capacity;
    cin >> capacity;
    cin.ignore();
    
    string msg1, msg2;
    getline(cin, msg1);
    getline(cin, msg2);

    // TODO: Crie um MessageLog chamado 'original' com a capacidade de entrada

    // TODO: Adicione ambas as mensagens a original

    // TODO: Crie uma cópia chamada 'backup' usando o construtor de cópia

    // TODO: Adicione "New message" apenas a original

    // TODO: Print "Original count: <count>"

    // TODO: Imprima "Backup count: <count>"

    // TODO: Imprima todas as mensagens de backup, uma por linha

    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C++ online