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 para 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 rasa (shallow copy) - ele copia o valor de cada membro diretamente. 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];              // Aloca nova memória
        for (size_t i = 0; i < size; i++)
            data[i] = other.data[i];       // Copia o conteúdo
    }
    
    ~Buffer() { delete[] data; }
};

Sem um construtor de cópia personalizado, ambos os objetos apontariam para a mesma memória. Quando um é 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 construir um sistema de histórico de mensagens que demonstra a importância da cópia profunda (deep copy) 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: Define 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 um count para o número atual de mensagens
    • Um construtor parametrizado que recebe uma capacidade, aloca o array no heap e inicializa o count como 0
    • Um construtor de cópia que realiza uma cópia profunda (deep copy) — alocando nova memória e copiando todas as mensagens do objeto de origem
    • Um destruidor 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 contagem 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, então:
    • Crie um MessageLog chamado original com a capacidade informada
    • Adicione ambas as mensagens ao original
    • Crie uma cópia chamada backup usando o construtor de cópia
    • Adicione uma terceira mensagem "New message" apenas ao original
    • Imprima "Original count: <count>"
    • Imprima "Backup count: <count>"
    • Imprima todas as mensagens do backup, uma por linha

O formato de 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 deve ter 2 mensagens enquanto o original tem 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 no main.cpp usando #include "MessageLog.h".

Experimente você mesmo

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

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

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

    // TODO: Adicionar ambas as mensagens ao original

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

    // TODO: Adicionar "New message" apenas ao original

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

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

    // TODO: Imprimir todas as mensagens do 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