Fácil C++
Formas geométricas
Enunciado
Crie uma classe base Forma com um método virtual area() que retorna 0.0. Depois, crie as classes Retangulo e Circulo que herdam publicamente de Forma e sobrescrevem area() com override. No main, crie um std::vector<std::unique_ptr<Forma>> com uma instância de cada e imprima a área de cada uma usando polimorfismo.
Requisitos
Formatem métodovirtual double area() constque retorna 0.0.RetanguloeCirculoherdam publicamente deFormae usamoverrideemarea().- O
mainusastd::unique_ptr<Forma>e chamaarea()polimorficamente. - A saída mostra as áreas calculadas corretamente.
Código inicial
#include <iostream>
#include <memory>
#include <vector>
// TODO: definir classes Forma, Retangulo, Circulo
int main() {
// TODO: criar vetor de unique_ptr<Forma> e imprimir áreas
return 0;
}
Saída esperada
Area do retangulo: 12
Area do circulo: 28.2743
Ver dica
Use 3.14159 como valor de π. Lembre-se de que area() deve ser const para poder ser chamada em objetos constantes.
Mostrar solução
#include <iostream>
#include <memory>
#include <vector>
class Forma {
public:
virtual double area() const {
return 0.0;
}
virtual ~Forma() = default; // destrutor virtual
};
class Retangulo : public Forma {
double largura_, altura_;
public:
Retangulo(double l, double a) : largura_(l), altura_(a) {}
double area() const override {
return largura_ * altura_;
}
};
class Circulo : public Forma {
double raio_;
public:
Circulo(double r) : raio_(r) {}
double area() const override {
return 3.14159 * raio_ * raio_;
}
};
int main() {
std::vector<std::unique_ptr<Forma>> formas;
formas.push_back(std::make_unique<Retangulo>(3.0, 4.0));
formas.push_back(std::make_unique<Circulo>(3.0));
for (const auto& f : formas) {
std::cout << "Area: " << f->area() << '\n';
}
return 0;
}
Passo a passo
- Definimos a classe base
Formacom um métodovirtual double area() constque retorna 0.0. Ovirtualpermite que as classes derivadas sobrescrevam esse método. - Incluímos um destrutor virtual
virtual ~Forma() = default;para garantir que, ao deletar um objeto via ponteiro paraForma, o destrutor correto da classe derivada seja chamado. - A classe
Retanguloherda publicamente deFormae armazena largura e altura. Seu construtor inicializa esses valores. - O método
area()emRetanguloé marcado comoverride, indicando que estamos sobrescrevendo o método virtual da base. Ele retorna o produto da largura pela altura. - A classe
Circulotambém herda publicamente deFormae armazena o raio. Seu métodoarea()retorna π vezes o raio ao quadrado. - No
main, criamos umstd::vector<std::unique_ptr<Forma>>e adicionamos umRetanguloe umCirculousandostd::make_unique. - Iteramos sobre o vetor e chamamos
f->area(). Devido ao polimorfismo, a versão correta dearea()é chamada para cada objeto. - A saída mostra as áreas calculadas: 12 para o retângulo (34) e aproximadamente 28.2743 para o círculo (π3²).
Por que funciona
O polimorfismo dinâmico é possível porque area() é virtual na classe base. Quando chamamos area() através de um ponteiro ou referência para Forma, o programa consulta a tabela virtual do objeto e invoca a implementação da classe derivada correspondente. O uso de std::unique_ptr<Forma> garante que os objetos sejam destruídos corretamente, desde que o destrutor seja virtual.
Erros comuns
- Esquecer
virtualna classe base: Searea()não for virtual, a chamadaf->area()sempre usará a versão deForma, retornando 0.0. Corrija declarandovirtual double area() const. - Não usar
override: Se a assinatura não coincidir exatamente (por exemplo, faltarconst), o método não sobrescreve e o compilador pode não avisar. Useoverridepara que o compilador verifique. - Destrutor não virtual: Se
~Forma()não for virtual, ao deletar umRetanguloviaunique_ptr<Forma>, apenas o destrutor deFormaseria chamado, causando vazamento de recursos da parte derivada. Declarevirtual ~Forma() = default;. - Esquecer
constno método: Searea()não forconst, não poderá ser chamado em objetos constantes ou referências constantes, como no loopfor (const auto& f : formas). Declaredouble area() const override.
Outra forma de resolver
Poderia-se usar std::variant ou herança múltipla, mas para polimorfismo clássico a herança com métodos virtuais é a abordagem idiomática. Uma alternativa é usar std::function para armazenar callables, mas isso foge do conceito de herança.
Saída esperada
Area do retangulo: 12
Area do circulo: 28.2743