C++: Prática: POO Abrangente
Última atualização: 2026-08-26
Nas 35 aulas anteriores, cobrimos muitos aspectos do C++.
Agora, é hora de juntar tudo.
Nesta aula, vamos construir um sistema completo de gerenciamento de alunos — da análise de requisitos à implementação de código, experimentando o desenvolvimento de software real.
1. Análise de Requisitos do Projeto
(1) 1.1 Requisitos Funcionais
O sistema de gerenciamento de alunos que estamos construindo tem as seguintes funcionalidades:
| Módulo de Funcionalidade | Funções Específicas |
|---|---|
| Gerenciamento de Alunos | Adicionar, excluir, modificar, buscar alunos |
| Gerenciamento de Notas | Inserir notas, calcular médias, ranking |
| Persistência de Dados | Salvar em arquivo, carregar de arquivo |
| Interface com Usuário | Interface de console baseada em menu |
(2) 1.2 Design de Classes
Com base nos requisitos, precisamos projetar as seguintes classes:
Student (Classe base)
↑ Herda
UndergraduateStudent (Graduando)
GraduateStudent (Pós-graduando)
Course (Classe de curso)
Grade (Classe de nota)
ManagementSystem (Classe do sistema de gerenciamento)
- vector<Student*> students
- vector<Course> courses
2. Implementação da Versão Básica
(1) 2.1 Design da Classe Student
Exemplo: Classe Student Versão Básica (Dificuldade ⭐⭐)
#include <iostream>
#include <string>
#include <vector>
// Classe base Student
class Student {
protected:
std::string id; // Matrícula
std::string name; // Nome
int age; // Idade
std::string major; // Curso
public:
// Construtor
Student(const std::string& id, const std::string& name, int age, const std::string& major)
: id(id), name(name), age(age), major(major) {}
// Função virtual: exibir informações
virtual void display() const {
std::cout << "Student ID: " << id << std::endl;
std::cout << "Name: " << name << std::endl;
std::cout << "Age: " << age << std::endl;
std::cout << "Major: " << major << std::endl;
}
// Destrutor virtual
virtual ~Student() {}
// Getter
std::string getId() const { return id; }
std::string getName() const { return name; }
};
// Classe Undergraduate
class UndergraduateStudent : public Student {
private:
int year; // Ano (1-4)
public:
UndergraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, int year)
: Student(id, name, age, major), year(year) {}
void display() const override {
Student::display();
std::cout << "Year: " << year << std::endl;
std::cout << "Type: Undergraduate" << std::endl;
}
};
// Classe GraduateStudent
class GraduateStudent : public Student {
private:
std::string advisor; // Orientador
public:
GraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, const std::string& advisor)
: Student(id, name, age, major), advisor(advisor) {}
void display() const override {
Student::display();
std::cout << "Advisor: " << advisor << std::endl;
std::cout << "Type: Graduate Student" << std::endl;
}
};
(2) 2.2 Classe do Sistema de Gerenciamento
Exemplo: Sistema de Gerenciamento Versão Básica (Dificuldade ⭐⭐⭐)
▶ Exemplo 1: Usando Contêineres STL (Dificuldade ⭐)
class ManagementSystem {
private:
std::vector<Student*> students; // Lista de alunos (polimorfismo)
public:
// Adicionar aluno
void addStudent(Student* student) {
students.push_back(student);
std::cout << "Added successfully!" << std::endl;
}
// Buscar aluno
Student* findStudent(const std::string& id) {
for (auto s : students) {
if (s->getId() == id) {
return s;
}
}
return nullptr;
}
// Exibir todos os alunos
void displayAll() const {
if (students.empty()) {
std::cout << "No student information available" << std::endl;
return;
}
for (auto s : students) {
s->display();
std::cout << "-------------------" << std::endl;
}
}
// Destrutor: liberar memória
~ManagementSystem() {
for (auto s : students) {
delete s;
}
}
};
// Código de teste
int main() {
ManagementSystem sys;
// Adicionar graduando
sys.addStudent(new UndergraduateStudent("001", "Zhang San", 20, "Computer Science", 3));
sys.addStudent(new GraduateStudent("002", "Li Si", 24, "Software Engineering", "Prof. Wang"));
// Exibir todos os alunos
sys.displayAll();
return 0;
}
Saída:
Added successfully!
No student information available
-------------------
Resultado da execução:
Added successfully!
Added successfully!
Student ID: 001
Name: Zhang San
Age: 20
Major: Computer Science
Year: 3
Type: Undergraduate
-------------------
Student ID: 002
Name: Li Si
Age: 24
Major: Software Engineering
Advisor: Prof. Wang
Type: Graduate Student
-------------------
3. Implementação da Versão Completa
(1) 3.1 Adicionando Mais Funcionalidades
Agora, vamos adicionar mais funcionalidades ao sistema:
| Funcionalidade | Implementação |
|---|---|
| Excluir aluno | Excluir por matrícula |
| Modificar informações | Buscar por matrícula, depois modificar |
| Gerenciamento de notas | Adicionar uma classe Grade |
| Salvar em arquivo | Usar ofstream para escrever arquivo |
| Carregar de arquivo | Usar ifstream para ler arquivo |
(2) 3.2 Design da Classe Grade
// Classe Grade
### ▶ Exemplo 2: Demo de Programação Orientada a Objetos (Dificuldade ⭐)
class Grade {
private:
std::string courseId; // ID do curso
std::string courseName; // Nome do curso
double score; // Nota
public:
Grade(const std::string& courseId, const std::string& courseName, double score)
: courseId(courseId), courseName(courseName), score(score) {}
void display() const {
std::cout << courseName << ": " << score << " points" << std::endl;
}
double getScore() const { return score; }
};
// Adicionar métodos relacionados a notas na classe Student
class Student {
// ... outros membros ...
std::vector<Grade> grades; // Lista de notas
public:
void addGrade(const Grade& grade) {
grades.push_back(grade);
}
void displayGrades() const {
if (grades.empty()) {
std::cout << "No grades available" << std::endl;
return;
}
std::cout << name << "'s grades:" << std::endl;
for (const auto& g : grades) {
g.display();
}
}
double getAverage() const {
if (grades.empty()) return 0.0;
double sum = 0;
for (const auto& g : grades) {
sum += g.getScore();
}
return sum / grades.size();
}
};
(3) 3.3 Operações com Arquivos
Salvar informações do aluno em arquivo:
void saveToFile(const std::string& filename) {
std::ofstream file(filename);
if (!file) {
std::cout << "Cannot open file" << std::endl;
return;
}
for (auto s : students) {
file << s->getId() << ","
<< s->getName() << ","
<< s->getAge() << std::endl;
}
file.close();
std::cout << "Saved successfully!" << std::endl;
}
Carregar de arquivo:
void loadFromFile(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
std::cout << "Cannot open file" << std::endl;
return;
}
std::string id, name, ageStr;
while (std::getline(file, id, ',')) {
std::getline(file, name, ',');
std::getline(file, ageStr);
int age = std::stoi(ageStr);
// Criar objeto aluno (simplificado; deveria distinguir graduando/pós-graduando)
students.push_back(new UndergraduateStudent(id, name, age, "Unknown", 1));
}
file.close();
std::cout << "Loaded successfully!" << std::endl;
}
4. Implementação da Interface de Menu
(1) 4.1 Menu Principal
void showMenu() {
std::cout << "\n===== Student Management System =====" << std::endl;
std::cout << "1. Add student" << std::endl;
std::cout << "2. Find student" << std::endl;
std::cout << "3. Display all students" << std::endl;
std::cout << "4. Enter grades" << std::endl;
std::cout << "5. Save data" << std::endl;
std::cout << "6. Load data" << std::endl;
std::cout << "0. Exit" << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << "Choose: ";
}
int main() {
ManagementSystem sys;
int choice;
do {
showMenu();
std::cin >> choice;
switch (choice) {
case 1:
// Adicionar aluno
break;
case 2:
// Buscar aluno
break;
case 3:
sys.displayAll();
break;
case 0:
std::cout << "Goodbye!" << std::endl;
break;
default:
std::cout << "Invalid choice" << std::endl;
}
} while (choice != 0);
return 0;
}
5. Sugestões de Extensão do Projeto
(1) 5.1 Extensões de Funcionalidade
| Funcionalidade | Dificuldade | Descrição |
|---|---|---|
| Estatísticas de Notas | ⭐⭐ | Calcular médias, rankings |
| Validação de Dados | ⭐⭐ | Verificar validade da entrada |
| Tratamento de Exceções | ⭐⭐⭐ | Usar try-catch para erros |
| GUI | ⭐⭐⭐⭐ | Usar Qt ou wxWidgets |
| Banco de Dados | ⭐⭐⭐⭐ | Usar SQLite ou MySQL |
(2) 5.2 Otimização de Código
| Otimização | Descrição |
|---|---|
| Smart Pointers | Usar unique_ptr para gerenciamento de memória |
| Correção Const | Usar const sempre que possível |
| Tratamento de Exceções | Usar try-catch para erros de arquivo |
| Sobrecarga de Operadores | Sobrecarregar << para saída |
▶ Exemplo 3: Hierarquia simples de herança de classes (Dificuldade ⭐)
#include <iostream>
#include <string>
class Animal {
public:
std::string name;
Animal(const std::string& n) : name(n) {}
virtual void speak() const = 0;
virtual ~Animal() {}
};
class Dog : public Animal {
public:
Dog(const std::string& n) : Animal(n) {}
void speak() const override {
std::cout << name << ": Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
Cat(const std::string& n) : Animal(n) {}
void speak() const override {
std::cout << name << ": Meow!" << std::endl;
}
};
int main() {
Dog dog("Wangcai");
Cat cat("Mimi");
dog.speak();
cat.speak();
return 0;
}
Saída:
: Woof!
: Meow!
❓ Perguntas Frequentes
P: Por que usar ponteiros para armazenar alunos? R: Para alcançar polimorfismo. Usar
vector<Student>causaria slicing de objetos, então apenas métodos da classe base poderiam ser chamados.
P: E sobre vazamentos de memória? R: Use smart pointers (
unique_ptr) para gerenciar memória automaticamente — sem necessidade dedeletemanual.
P: Como devo projetar o formato de arquivo? R: Você pode usar: - Formato CSV: simples, mas funcionalidade limitada - Formato JSON: poderoso, requer biblioteca de terceiros - Formato binário: eficiente, mas não legível por humanos
P: Como lidar com caracteres chineses? R: O C++ tem suporte limitado para chinês. Sugestões: - Usar
wstring+wcout- Ou usar uma biblioteca de terceiros (ex.: iconv) - Ou armazenar apenas pinyin/inglês
📖 Resumo
| Ponto de Conhecimento | Ponto-Chave |
|---|---|
| Design de Classes | Classe base + classe derivada, refletindo herança |
| Polimorfismo | Usar ponteiros/referências para chamar funções virtuais |
| Operações com Arquivos | ofstream para escrita, ifstream para leitura |
| Gerenciamento de Memória | Destrutor libera memória (ou use smart pointers) |
| Interface de Menu | do-while + switch |
Sugestões de estudo:
- Este projeto é um exercício abrangente — certifique-se de digitá-lo você mesmo
- Implemente funcionalidades básicas primeiro, depois estenda gradualmente
- Ao encontrar problemas, pesquise soluções primeiro — desenvolva habilidades de resolução de problemas
📝 Exercícios
-
Básico (Dificuldade ⭐): Defina uma classe Book (título, autor, preço), crie 3 objetos e exiba suas propriedades.
-
Intermediário (Dificuldade ⭐⭐): Implemente uma hierarquia de herança: Shape (classe base, função virtual pura area()) → classes derivadas Circle e Rectangle. Chame area() polimorficamente.
-
Desafio (Dificuldade ⭐⭐⭐): Implemente um "padrão Observer": classe Subject mantém uma lista de Observer, Observer é uma classe base abstrata. Quando o estado de Subject muda, notifique todos os Observers.
- Esta seção cobriu os conceitos centrais da prática de POO
- Com domínio, você pode escrever programas C++ relacionados
Fase 5 completa! Próxima: Fase 6 (STL Avançado)