Médio C++
Funcionários e bônus
Enunciado
Crie uma hierarquia de classes para representar funcionários. A classe base Funcionario deve ter um método virtual calcularBonus() const que retorna 0.0 e um método nome() const que retorna o nome. As classes Gerente e Desenvolvedor herdam de Funcionario e sobrescrevem calcularBonus(): Gerente recebe 20% do salário base, Desenvolvedor recebe 10%. Use override e garanta que o destrutor seja virtual. No main, crie um vetor de std::unique_ptr<Funcionario>, adicione um gerente e um desenvolvedor, e imprima o nome e o bônus de cada um.
Requisitos
Funcionariotem métodovirtual double calcularBonus() constque retorna 0.0 e métodovirtual std::string nome() const.GerenteeDesenvolvedorherdam publicamente deFuncionarioe usamoverrideemcalcularBonus().- O destrutor de
Funcionarioé virtual. - O
mainusastd::unique_ptr<Funcionario>e chamanome()ecalcularBonus()polimorficamente. - A saída mostra os nomes e bônus corretos.
Código inicial
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// TODO: definir classes Funcionario, Gerente, Desenvolvedor
int main() {
// TODO: criar vetor de unique_ptr<Funcionario> e imprimir nome e bônus
return 0;
}
Saída esperada
Nome: Ana, Bonus: 2000
Nome: Bruno, Bonus: 500
Ver dica
O salário base pode ser passado no construtor de cada classe derivada. Lembre-se de que nome() também pode ser virtual para permitir personalização.
Mostrar solução
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Funcionario {
protected:
std::string nome_;
double salarioBase_;
public:
Funcionario(std::string nome, double salarioBase)
: nome_(std::move(nome)), salarioBase_(salarioBase) {}
virtual double calcularBonus() const {
return 0.0;
}
virtual std::string nome() const {
return nome_;
}
virtual ~Funcionario() = default; // destrutor virtual
};
class Gerente : public Funcionario {
public:
Gerente(std::string nome, double salarioBase)
: Funcionario(std::move(nome), salarioBase) {}
double calcularBonus() const override {
return salarioBase_ * 0.20;
}
};
class Desenvolvedor : public Funcionario {
public:
Desenvolvedor(std::string nome, double salarioBase)
: Funcionario(std::move(nome), salarioBase) {}
double calcularBonus() const override {
return salarioBase_ * 0.10;
}
};
int main() {
std::vector<std::unique_ptr<Funcionario>> funcionarios;
funcionarios.push_back(std::make_unique<Gerente>("Ana", 10000.0));
funcionarios.push_back(std::make_unique<Desenvolvedor>("Bruno", 5000.0));
for (const auto& f : funcionarios) {
std::cout << "Nome: " << f->nome()
<< ", Bonus: " << f->calcularBonus() << '\n';
}
return 0;
}
Passo a passo
- A classe
Funcionariopossui membros protegidosnome_esalarioBase_, acessíveis pelas classes derivadas. O construtor inicializa esses valores. - O método
calcularBonus()é virtual e retorna 0.0 por padrão. Isso permite que as classes derivadas forneçam implementações específicas. - O método
nome()também é virtual e retorna o nome armazenado. Embora não seja sobrescrito aqui, poderia ser em outras subclasses. - O destrutor virtual
virtual ~Funcionario() = default;garante que ao deletar um objeto via ponteiro paraFuncionario, o destrutor da classe derivada seja chamado, liberando recursos corretamente. - A classe
Gerenteherda publicamente deFuncionarioe sobrescrevecalcularBonus()comoverride, retornando 20% do salário base. - A classe
Desenvolvedortambém herda publicamente e sobrescrevecalcularBonus()retornando 10% do salário base. - No
main, criamos umstd::vector<std::unique_ptr<Funcionario>>e adicionamos umGerentee umDesenvolvedorcomstd::make_unique. - Iteramos sobre o vetor e imprimimos o nome e o bônus de cada funcionário. Devido ao polimorfismo, as versões corretas de
calcularBonus()são chamadas.
Por que funciona
A herança pública estabelece a relação "é um": Gerente e Desenvolvedor são Funcionario. O método virtual calcularBonus() permite que cada subclasse forneça seu próprio cálculo. O uso de std::unique_ptr<Funcionario> garante que os objetos sejam destruídos corretamente, desde que o destrutor seja virtual. O override assegura que estamos realmente sobrescrevendo o método da base, evitando erros de digitação na assinatura.
Erros comuns
- Não tornar
calcularBonus()virtual: Se não for virtual, a chamadaf->calcularBonus()sempre usaria a versão deFuncionario, retornando 0.0. Declarevirtual double calcularBonus() const. - Esquecer
override: Se a assinatura não coincidir (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
~Funcionario()não for virtual, ao deletar umGerenteviaunique_ptr<Funcionario>, apenas o destrutor deFuncionarioseria chamado, causando vazamento de recursos. Declarevirtual ~Funcionario() = default;. - Acessar membros privados da base: Se
nome_esalarioBase_fossem privados, as classes derivadas não poderiam acessá-los. Useprotectedpara permitir acesso controlado.
Outra forma de resolver
Poderia-se usar uma função virtual pura (= 0) para tornar Funcionario uma classe abstrata, forçando as subclasses a implementar calcularBonus(). Isso é útil quando não faz sentido instanciar a base. Exemplo: virtual double calcularBonus() const = 0;. No entanto, o enunciado não exige isso.
Saída esperada
Nome: Ana, Bonus: 2000
Nome: Bruno, Bonus: 500