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:

TEXT 📖 Somente leitura
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 ⭐⭐)

TEXT 📖 Somente leitura
#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 ⭐)

CPP
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;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Added successfully!
No student information available
-------------------

Resultado da execução:

TEXT 📖 Somente leitura
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

TEXT 📖 Somente leitura
// 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:

CPP
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:

TEXT 📖 Somente leitura
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

CPP
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 ⭐)

CPP
#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;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
: 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 de delete manual.


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:


📝 Exercícios

  1. Básico (Dificuldade ⭐): Defina uma classe Book (título, autor, preço), crie 3 objetos e exiba suas propriedades.

  2. 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.

  3. 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.



Fase 5 completa! Próxima: Fase 6 (STL Avançado)

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%