C++: Prática: Sistema de Agenda
Última atualização: 2026-08-26
Na aula 50, aprendemos sobre testes unitários.
Agora, vamos construir nosso primeiro projeto prático abrangente — um sistema de agenda.
Este projeto integrará todo o conhecimento que você aprendeu até agora.
1. Requisitos do Projeto
(1) 1.1 Requisitos Funcionais
| Funcionalidade | Descrição |
|---|---|
| Adicionar contato | Inserir nome, telefone, email |
| Excluir contato | Excluir por nome ou telefone |
| Modificar contato | Atualizar informações |
| Buscar contato | Pesquisar por nome ou telefone |
| Exibir todos | Listar todos os contatos |
| Salvar/Carregar | Persistir em arquivo |
(2) 1.2 Design de Classes
Contact
- name, phone, email
AddressBook
- vector<Contact> contacts
- add, remove, update, find, display
- save, load
2. Classe Contact
(1) 2.1 Definição da Classe Contact
#include <iostream>
#include <string>
#include <fstream>
class Contact {
private:
std::string name;
std::string phone;
std::string email;
public:
Contact() = default;
Contact(const std::string& name, const std::string& phone, const std::string& email)
: name(name), phone(phone), email(email) {}
// Getter
std::string getName() const { return name; }
std::string getPhone() const { return phone; }
std::string getEmail() const { return email; }
// Setter
void setName(const std::string& n) { name = n; }
void setPhone(const std::string& p) { phone = p; }
void setEmail(const std::string& e) { email = e; }
// Exibir
void display() const {
std::cout << "Name: " << name << std::endl;
std::cout << "Phone: " << phone << std::endl;
std::cout << "Email: " << email << std::endl;
std::cout << "-------------------" << std::endl;
}
// Serializar (salvar em arquivo)
void save(std::ofstream& file) const {
file << name << "," << phone << "," << email << std::endl;
}
// Desserializar (carregar de arquivo)
static Contact load(std::ifstream& file) {
Contact c;
std::getline(file, c.name, ',');
std::getline(file, c.phone, ',');
std::getline(file, c.email);
return c;
}
};
3. Classe Agenda
(1) 3.1 Definição da Classe AddressBook
▶ Exemplo 1: Usando Contêineres STL (Dificuldade ⭐)
#include <vector>
#include <algorithm>
class AddressBook {
private:
std::vector<Contact> contacts;
public:
// Adicionar contato
void addContact(const Contact& c) {
contacts.push_back(c);
std::cout << "Added successfully!" << std::endl;
}
// Buscar contato (por nome)
Contact* findByName(const std::string& name) {
for (auto& c : contacts) {
if (c.getName() == name) {
return &c;
}
}
return nullptr;
}
// Excluir contato (por nome)
bool removeByName(const std::string& name) {
auto it = std::remove_if(contacts.begin(), contacts.end(),
[&name](const Contact& c) {
return c.getName() == name;
});
if (it != contacts.end()) {
contacts.erase(it, contacts.end());
std::cout << "Deleted successfully!" << std::endl;
return true;
}
std::cout << "Contact not found: " << name << std::endl;
return false;
}
// Exibir todos os contatos
void displayAll() const {
if (contacts.empty()) {
std::cout << "Address book is empty" << std::endl;
return;
}
for (const auto& c : contacts) {
c.display();
}
}
// Salvar em arquivo
void saveToFile(const std::string& filename) const {
std::ofstream file(filename);
if (!file) {
std::cerr << "Cannot open file" << std::endl;
return;
}
for (const auto& c : contacts) {
c.save(file);
}
file.close();
std::cout << "Saved successfully!" << std::endl;
}
// Carregar de arquivo
void loadFromFile(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
std::cerr << "Cannot open file" << std::endl;
return;
}
contacts.clear(); // Limpar dados existentes
std::string line;
while (file.peek() != EOF) {
contacts.push_back(Contact::load(file));
}
file.close();
std::cout << "Loaded successfully!" << std::endl;
}
};
Saída:
Added successfully!
Deleted successfully!
Contact not found:
Address book is empty
Saved successfully!
Loaded successfully!
4. Menu Principal
(1) 4.1 Implementação do Menu
void showMenu() {
### ▶ Exemplo 2: Prática Básica de Programação (Dificuldade ⭐)
std::cout << "\n===== Address Book Management System =====" << std::endl;
std::cout << "1. Add contact" << std::endl;
std::cout << "2. Delete contact" << std::endl;
std::cout << "3. Find contact" << std::endl;
std::cout << "4. Display all contacts" << std::endl;
std::cout << "5. Save" << std::endl;
std::cout << "6. Load" << std::endl;
std::cout << "0. Exit" << std::endl;
std::cout << "==========================================" << std::endl;
std::cout << "Choose: ";
}
int main() {
AddressBook book;
int choice;
do {
showMenu();
std::cin >> choice;
switch (choice) {
case 1: {
std::string name, phone, email;
std::cout << "Name: ";
std::cin >> name;
std::cout << "Phone: ";
std::cin >> phone;
std::cout << "Email: ";
std::cin >> email;
book.addContact(Contact(name, phone, email));
break;
}
case 2: {
std::string name;
std::cout << "Name: ";
std::cin >> name;
book.removeByName(name);
break;
}
case 3: {
std::string name;
std::cout << "Name: ";
std::cin >> name;
Contact* c = book.findByName(name);
if (c) {
c->display();
} else {
std::cout << "Not found" << std::endl;
}
break;
}
case 4:
book.displayAll();
break;
case 5: {
book.saveToFile("contacts.txt");
break;
}
case 6: {
book.loadFromFile("contacts.txt");
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
(1) 5.1 Extensões de Funcionalidade
| Funcionalidade | Dificuldade |
|---|---|
| Buscar por telefone | ⭐ |
| Modificar contato | ⭐⭐ |
| Ordenar por nome | ⭐⭐ |
| Importar/Exportar CSV | ⭐⭐⭐ |
| GUI | ⭐⭐⭐⭐ |
❓ Exercícios
(1) Exercício Básico (Dificuldade ⭐)
Adicione um recurso de "busca por telefone" à agenda.
(2) Exercício Intermediário (Dificuldade ⭐⭐)
Adicione um recurso de "modificar contato" à agenda.
(3) Exercício Desafio (Dificuldade ⭐⭐⭐)
Refatore a agenda usando std::map para melhorar a eficiência de busca.
▶ Exemplo 3: Definição de Struct Contact (Dificuldade ⭐)
#include <iostream>
#include <string>
struct Contact {
std::string name;
std::string phone;
std::string email;
void display() const {
std::cout << "Name: " << name << std::endl;
std::cout << "Phone: " << phone << std::endl;
std::cout << "Email: " << email << std::endl;
}
};
int main() {
Contact c1 = {"Zhang San", "13800138000", "zhangsan@example.com"};
Contact c2 = {"Li Si", "13900139000", "lisi@example.com"};
c1.display();
std::cout << "---" << std::endl;
c2.display();
return 0;
}
Saída:
Name:
Phone:
Email:
---
❓ Perguntas Frequentes
P: Por que usar vector em vez de arrays? R: vector redimensiona automaticamente, então você não precisa saber o número de elementos antecipadamente. O tamanho de um array deve ser determinado em tempo de compilação, enquanto vector pode crescer e encolher flexivelmente em tempo de execução. P: Por que usar um struct para informações de contato em vez de múltiplos arrays? R: Structs empacotam dados relacionados juntos, tornando a lógica mais clara. Com múltiplos arrays, operações de adição/exclusão são propensas a erros (ex.: excluir um nome mas esquecer de excluir o telefone). P: No que devo prestar atenção com I/O de arquivos? R: ① Verifique se o arquivo abriu com sucesso (is_open); ② Feche após escrever (close()); ③ Use eof() ou good() em loops de leitura para evitar loops infinitos; ④ Use tratamento de exceções para garantir que os arquivos sejam fechados corretamente.
📖 Resumo
| Ponto de Conhecimento | Aplicação |
|---|---|
| Orientação a Objetos | Classes Contact e AddressBook |
| STL | vector para armazenar contatos |
| Operações com Arquivos | Salvar/Carregar |
| Processamento de Strings | Analisar CSV |
- Sistema de agenda: quatro operações CRUD centrais
- Usar structs para armazenar informações de contatos
- Contêiner vector para gerenciar dados dinâmicos
- I/O de arquivo para persistência de dados
- Funções modulares encapsulam cada funcionalidade
📝 Exercícios
-
Básico (Dificuldade ⭐): Execute o programa de agenda, adicione 3 contatos (nome, telefone, grupo) e visualize a exibição. Tente usar o recurso "editar" para modificar as informações de um contato.
-
Intermediário (Dificuldade ⭐⭐): Adicione um recurso de "contato favorito" à agenda — adicione um campo
bool isFavoriteao struct e marque contatos favoritos com[★]ao exibir a lista. -
Desafio (Dificuldade ⭐⭐⭐): Implemente um recurso de "busca difusa": após o usuário inserir uma palavra-chave, corresponda todos os contatos cujos nomes contenham a palavra-chave e exiba-os. Se a entrada estiver vazia, mostre todos os contatos. Suporte correspondência insensível a maiúsculas/minúsculas.
Próxima aula: Prática: Banco de Dados Simples (#52)