Estudo de caso: Montagem de computadores com polimorfismo em C++

O objetivo deste exemplo é modelar os componentes de um computador (CPU, placa de vídeo e memória) utilizando classes abstratas, e depois montar diferentes configurações por meio de poilmorfismo e composição.

// Primeira versão (com erros conceituais)
#include <iostream>
using namespace std;

// 1. Classes abstratas para cada componente
class CPU {
public:
    virtual void calcular() = 0;
};

class PlacaVideo {
public:
    virtual void exibir() = 0;
};

class Memoria {
public:
    virtual void armazenar() = 0;
};

// 2. Fabricantes específicos (exemplo com erros: herança múltipla indevida)
class IntelCPU : public CPU {
public:
    IntelCPU() { cout << "CPU Intel" << endl; }
    virtual void calcular() override { cout << "Intel processando" << endl; }
    virtual ~IntelCPU() = 0;
};
IntelCPU::~IntelCPU() { cout << "Destrutor IntelCPU" << endl; }

class NVIDIA : public PlacaVideo {
public:
    NVIDIA() { cout << "GPU NVIDIA" << endl; }
    virtual void exibir() override { cout << "NVIDIA renderizando" << endl; }
    virtual ~NVIDIA() = 0;
};
NVIDIA::~NVIDIA() { cout << "Destrutor NVIDIA" << endl; }

class Samsung : public Memoria {
public:
    Samsung() { cout << "Memória Samsung" << endl; }
    virtual void armazenar() override { cout << "Samsung armazenando" << endl; }
    virtual ~Samsung() = 0;
};
Samsung::~Samsung() { cout << "Destrutor Samsung" << endl; }

// 3. Classe Computador (incorretamente derivada dos componentes concretos)
class Computador : public IntelCPU, public NVIDIA, public Samsung {
public:
    Computador(string cpu, string gpu, string mem) {
        m_cpu = new string(cpu);
        m_gpu = new string(gpu);
        m_mem = new string(mem);
    }
    void montar() {
        calcular();
        exibir();
        armazenar();
    }
    ~Computador() {
        if (m_cpu) { delete m_cpu; m_cpu = nullptr; }
        if (m_gpu) { delete m_gpu; m_gpu = nullptr; }
        if (m_mem) { delete m_mem; m_mem = nullptr; }
    }
    string* m_cpu;
    string* m_gpu;
    string* m_mem;
};

void teste() {
    Computador* pc = new Computador("Intel", "NVIDIA", "Samsung");
    pc->montar();
    delete pc;
}

int main() {
    teste();
    return 0;
}

O código acima contém dois problemas principais: herança múltipla de classes concretas (em vez de composição) e destruidores virtuais puros desnecessários. A correção adequada utiliza composição com ponteiros para as classes abstratas:

// Versão corrigida
#include <iostream>
using namespace std;

// 1. Classes abstratas (mesmas)
class CPU {
public:
    virtual void calcular() = 0;
};

class PlacaVideo {
public:
    virtual void exibir() = 0;
};

class Memoria {
public:
    virtual void armazenar() = 0;
};

// 2. Fabricantes (sem destruidores virtuais puros)
class IntelCPU : public CPU {
public:
    virtual void calcular() override { cout << "IntelCPU processando" << endl; }
};

class NVIDIA : public PlacaVideo {
public:
    virtual void exibir() override { cout << "NVIDIA renderizando" << endl; }
};

class Samsung : public Memoria {
public:
    virtual void armazenar() override { cout << "Samsung armazenando" << endl; }
};

// 3. Classe Computador usando composição
class Computador {
public:
    Computador(CPU* cpu, PlacaVideo* gpu, Memoria* mem) {
        m_cpu = cpu;
        m_gpu = gpu;
        m_mem = mem;
    }
    void montar() {
        m_cpu->calcular();
        m_gpu->exibir();
        m_mem->armazenar();
    }
    ~Computador() {
        if (m_cpu) { delete m_cpu; m_cpu = nullptr; }
        if (m_gpu) { delete m_gpu; m_gpu = nullptr; }
        if (m_mem) { delete m_mem; m_mem = nullptr; }
    }
private:
    CPU* m_cpu;
    PlacaVideo* m_gpu;
    Memoria* m_mem;
};

void teste() {
    CPU* cpu = new IntelCPU;
    PlacaVideo* gpu = new NVIDIA;
    Memoria* mem = new Samsung;

    Computador* pc = new Computador(cpu, gpu, mem);
    pc->montar();
    delete pc;  // deleta o computador e automaticamente os componentes
}

int main() {
    teste();
    return 0;
}

Na versão corrigida, a classe Computador recebe ponteiros para as bases abstratas, permitindo que qualquer combinação de fabricantes seja usada. A responsabilidade de deletar os componentes pode ser mantida no destruter do computador ou transferida para o chamador – no exemplo, o destruter do computador também libera os componentes.

Tags: C++ Polimorfismo Classes Abstratas composicao Herança

Publicado em 7-2 02:59