- Implementação com Composição
Esta seção apresenta uma implementação da classe GradeCalc utilizando o conceito de composição para gerenciar notas acadêmicas.
#pragma once
#include <vector>
#include <array>
#include <string>
class GradeCalc {
public:
GradeCalc(const std::string &cname);
void input(int n); // Registra n notas
void output() const; // Exibe as notas
void sort(bool ascending = false); // Ordena (decrescente por padrão)
int min() const; // Retorna nota mínima (-1 se não houver notas)
int max() const; // Retorna nota máxima (-1 se não houver notas)
double average() const; // Retorna média (0.0 se não houver notas)
void info(); // Mostra informações das notas
private:
void compute(); // Estatísticas das notas
private:
std::string course_name; // Nome da disciplina
std::vector<int> grades; // Notas da disciplina
std::array<int, 5> counts; // Contagem por faixas ([0,60), [60,70), [70,80), [80,90), [90,100])
std::array<double, 5> rates; // Percentual por faixa
bool is_dirty; // Indicador de alteração nas notas
};
#include <algorithm>
#include <array>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include "GradeCalc.hpp"
GradeCalc::GradeCalc(const std::string &cname): course_name{cname}, is_dirty{true} {
counts.fill(0);
rates.fill(0.0);
}
void GradeCalc::input(int n) {
if(n < 0) {
std::cerr << "Entrada inválida! Número de alunos não pode ser negativo\n";
std::exit(1);
}
grades.reserve(n);
int nota;
for(int i = 0; i < n;) {
std::cin >> nota;
if(nota < 0 || nota > 100) {
std::cerr << "Nota inválida! Deve estar entre 0 e 100\n";
continue;
}
grades.push_back(nota);
++i;
}
is_dirty = true;
}
void GradeCalc::output() const {
for(auto nota: grades)
std::cout << nota << ' ';
std::cout << std::endl;
}
void GradeCalc::sort(bool ascending) {
if(ascending)
std::sort(grades.begin(), grades.end());
else
std::sort(grades.begin(), grades.end(), std::greater<int>());
}
int GradeCalc::min() const {
if(grades.empty())
return -1;
auto it = std::min_element(grades.begin(), grades.end());
return *it;
}
int GradeCalc::max() const {
if(grades.empty())
return -1;
auto it = std::max_element(grades.begin(), grades.end());
return *it;
}
double GradeCalc::average() const {
if(grades.empty())
return 0.0;
double media = std::accumulate(grades.begin(), grades.end(), 0.0) / grades.size();
return media;
}
void GradeCalc::info() {
if(is_dirty)
compute();
std::cout << "Disciplina:\t" << course_name << std::endl;
std::cout << "Média:\t" << std::fixed << std::setprecision(2) << average() << std::endl;
std::cout << "Máxima:\t" << max() << std::endl;
std::cout << "Mínima:\t" << min() << std::endl;
const std::array<std::string, 5> faixas{"[0, 60) ",
"[60, 70)",
"[70, 80)",
"[80, 90)",
"[90, 100]"};
for(int i = static_cast<int>(faixas.size())-1; i >= 0; --i)
std::cout << faixas[i] << "\t: " << counts[i] << " alunos\t"
<< std::fixed << std::setprecision(2) << rates[i]*100 << "%\n";
}
void GradeCalc::compute() {
if(grades.empty())
return;
counts.fill(0);
rates.fill(0.0);
for(auto nota:grades) {
if(nota < 60)
++counts[0];
else if (nota < 70)
++counts[1];
else if (nota < 80)
++counts[2];
else if (nota < 90)
++counts[3];
else
++counts[4];
}
for(size_t i = 0; i < rates.size(); ++i)
rates[i] = counts[i] * 1.0 / grades.size();
is_dirty = false;
}
#include <iostream>
#include <string>
#include "GradeCalc.hpp"
void teste() {
GradeCalc calc("POO");
std::cout << "Inserindo notas:\n";
calc.input(5);
std::cout << "Notas registradas:\n";
calc.output();
std::cout << "Notas ordenadas:\n";
calc.sort(); calc.output();
std::cout << "*************Estatísticas*************\n";
calc.info();
}
int main() {
teste();
}
Análise de Conceitos
Relacionamento de Composição: A classe GradeCalc incorpora objetos de string, vector e array diretamente como membros, representando uma relação "tem um".
Exposição de Interface: Métodos privados como push_back do vector não são acessíveis externamente, mantendo o encapsulamento.
Gerenciamento de Estado: O flag is_dirty otimiza a atualização de estatísticas, evitando recálculos desnecessários.
- Implemantação com Herança
Nesta abordagem, a classe GradeCalc herda funcionalidades da std::vector<int> para gerenciar as notas.
#pragma once
#include <array>
#include <string>
#include <vector>
class GradeCalc: private std::vector<int> {
public:
GradeCalc(const std::string &cname);
void input(int n);
void output() const;
void sort(bool ascending = false);
int min() const;
int max() const;
double average() const;
void info();
private:
void compute();
private:
std::string course_name;
std::array<int, 5> counts;
std::array<double, 5> rates;
bool is_dirty;
};
#include <algorithm>
#include <array>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include "GradeCalc.hpp"
GradeCalc::GradeCalc(const std::string &cname): course_name{cname}, is_dirty{true}{
counts.fill(0);
rates.fill(0);
}
void GradeCalc::input(int n) {
if(n < 0) {
std::cerr << "Erro: número inválido de alunos\n";
return;
}
this->reserve(n);
int valor;
for(int i = 0; i < n;) {
std::cin >> valor;
if(valor < 0 || valor > 100) {
std::cerr << "Nota deve estar entre 0 e 100\n";
continue;
}
this->push_back(valor);
++i;
}
is_dirty = true;
}
void GradeCalc::output() const {
for(auto nota: *this)
std::cout << nota << ' ';
std::cout << std::endl;
}
void GradeCalc::sort(bool ascending) {
if(ascending)
std::sort(this->begin(), this->end());
else
std::sort(this->begin(), this->end(), std::greater<int>());
}
int GradeCalc::min() const {
if(this->empty())
return -1;
return *std::min_element(this->begin(), this->end());
}
int GradeCalc::max() const {
if(this->empty())
return -1;
return *std::max_element(this->begin(), this->end());
}
double GradeCalc::average() const {
if(this->empty())
return 0.0;
double media = std::accumulate(this->begin(), this->end(), 0.0) / this->size();
return media;
}
void GradeCalc::info() {
if(is_dirty)
compute();
std::cout << "Curso:\t" << course_name << std::endl;
std::cout << "Média:\t" << std::fixed << std::setprecision(2) << average() << std::endl;
std::cout << "Melhor:\t" << max() << std::endl;
std::cout << "Pior:\t" << min() << std::endl;
const std::array<std::string, 5> intervalos{"[0, 60) ",
"[60, 70)",
"[70, 80)",
"[80, 90)",
"[90, 100]"};
for(int i = static_cast<int>(intervalos.size())-1; i >= 0; --i)
std::cout << intervalos[i] << "\t: " << counts[i] << " estudantes\t"
<< std::fixed << std::setprecision(2) << rates[i]*100 << "%\n";
}
void GradeCalc::compute() {
if(this->empty())
return;
counts.fill(0);
rates.fill(0);
for(int nota: *this) {
if(nota < 60)
++counts[0];
else if (nota < 70)
++counts[1];
else if (nota < 80)
++counts[2];
else if (nota < 90)
++counts[3];
else
++counts[4];
}
for(size_t i = 0; i < rates.size(); ++i)
rates[i] = counts[i] * 1.0 / this->size();
is_dirty = false;
}
Comparação de Abordagens
A herança privada limita o acesso aos métodos da classe base, diferentemente da composição onde os membros são explicitamente encapsulados.
- Sistema de Renderização Gráfica
Este exemplo demonstra polimorfismo através de classes asbtratas e funções virtuais para desenhar formas geométricas.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
// Declarações de classes abstratas
class Graph {
public:
virtual ~Graph() = default;
virtual void draw() = 0;
};
enum class GraphType {circle, triangle, rectangle};
class Circle : public Graph {
public:
void draw() override { std::cout << "Desenhando círculo...\n"; }
};
class Triangle : public Graph {
public:
void draw() override { std::cout << "Desenhando triângulo...\n"; }
};
class Rectangle : public Graph {
public:
void draw() override { std::cout << "Desenhando retângulo...\n"; }
};
class Canvas {
public:
void add(const std::string& type);
void paint() const;
~Canvas();
private:
std::vector<Graph*> graphs;
};
GraphType str_to_GraphType(const std::string& s);
Graph* make_graph(const std::string& type);
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include "Graph.hpp"
void Circle::draw() { std::cout << "Desenhando círculo...\n"; }
void Triangle::draw() { std::cout << "Desenhando triângulo...\n"; }
void Rectangle::draw() { std::cout << "Desenhando retângulo...\n"; }
void Canvas::add(const std::string& type) {
Graph* figura = make_graph(type);
if (figura)
graphs.push_back(figura);
}
void Canvas::paint() const {
for (Graph* figura : graphs)
figura->draw();
}
Canvas::~Canvas() {
for (Graph* figura : graphs)
delete figura;
}
GraphType str_to_GraphType(const std::string& s) {
std::string t = s;
std::transform(s.begin(), s.end(), t.begin(),
[](unsigned char c) { return std::tolower(c);});
if (t == "circle")
return GraphType::circle;
if (t == "triangle")
return GraphType::triangle;
if (t == "rectangle")
return GraphType::rectangle;
return GraphType::circle;
}
Graph* make_graph(const std::string& type) {
switch (str_to_GraphType(type)) {
case GraphType::circle: return new Circle;
case GraphType::triangle: return new Triangle;
case GraphType::rectangle: return new Rectangle;
default: return nullptr;
}
}
#include <string>
#include "Graph.hpp"
void teste() {
Canvas tela;
tela.add("circle");
tela.add("triangle");
tela.add("rectangle");
tela.paint();
}
int main() {
teste();
}
- Sistema de Brinquedos Eletrônicos
Modelagem orientada a objetos aplicada a um sistema de controle de brinquedos interativos.
#include<iostream>
#include<vector>
#include<string>
class Toy{
private:
std::string nome;
std::string tipo;
double preco;
int quantidade;
public:
Toy(std::string n,std::string t,double p,int q):
nome(n),tipo(t),preco(p),quantidade(q){}
virtual ~Toy()=default;
virtual void mostrar()const {
std::cout<<"Nome:"<<nome<<" Tipo:"<<tipo<<" Preço:"
<<preco<<" R$ Qtde:"<<quantidade<<std::endl;
};
virtual void habilidade()const =0;
};
class DanceToy:public Toy{
public:
DanceToy(std::string nome,double preco,int qtde):
Toy(nome,"Dança",preco,qtde){}
void habilidade()const override{
std::cout<<"Habilidade Especial: Dança elegante."<<std::endl;
}
};
class MusicToy:public Toy{
public:
MusicToy(std::string nome,double preco,int qtde):
Toy(nome,"Música",preco,qtde){}
void habilidade()const override{
std::cout<<"Habilidade Especial: Toca música."<<std::endl;
}
};
class LightToy:public Toy{
public:
LightToy(std::string nome,double preco,int qtde):
Toy(nome,"Luz",preco,qtde){}
void habilidade()const override{
std::cout<<"Habilidade Especial: Emite luz."<<std::endl;
}
};
class ToyFactory{
public:
void incluir(Toy* brinquedo);
void listar()const;
~ToyFactory();
private:
std::vector<Toy*> estoque;
};
#include<iostream>
#include<vector>
#include<string>
#include "Toy.hpp"
void ToyFactory::incluir(Toy* brinquedo) {
estoque.push_back(brinquedo);
}
void ToyFactory::listar() const {
std::cout<<"\nBrinquedos na fábrica:\n";
for(auto* item:estoque){
item->mostrar();
item->habilidade();
std::cout<<std::endl;
}
}
ToyFactory::~ToyFactory() {
for(auto &item:estoque) delete item;
}
#include<iostream>
#include "Toy.hpp"
int main() {
ToyFactory fabrica;
fabrica.incluir(new DanceToy("Urso",88.5,6));
fabrica.incluir(new MusicToy("Pássaro",66.0,10));
fabrica.incluir(new LightToy("Gato",77.3,15));
fabrica.listar();
return 0;
}