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.