C++: 实战:通讯录系统

最后更新:2026-08-26

第50课我们学了单元测试。

现在,我们要做第一个综合实战项目——通讯录系统。

这个项目会综合运用前面学到的所有知识。


1. 项目需求

(1) 1.1 功能需求

功能 说明
添加联系人 输入姓名、电话、邮箱
删除联系人 按姓名或电话删除
修改联系人 修改信息
查找联系人 按姓名或电话查找
显示所有 列出所有联系人
保存/加载 持久化到文件

(2) 1.2 类的设计

TEXT 📖 仅展示
Contact(联系人)
 - name, phone, email

AddressBook(通讯录)
 - vectorContact contacts
 - add, remove, update, find, display
 - save, load


2. 联系人类

(1) 2.1 Contact类定义

CPP
#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; }
 
 // 显示
 void display() const {
 std::cout << "姓名:" << name << std::endl;
 std::cout << "电话:" << phone << std::endl;
 std::cout << "邮箱:" << email << std::endl;
 std::cout << "-------------------" << std::endl;
 }
 
 // 序列化(保存到文件)
 void save(std::ofstream& file) const {
 file << name << "," << phone << "," << email << std::endl;
 }
 
 // 反序列化(从文件加载)
 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. 通讯录类

(1) 3.1 AddressBook类定义

▶ 示例 1:STL容器使用(难度⭐)

CPP 📖 仅展示
#include <vector>
#include <algorithm>

class AddressBook {
private:
 std::vectorContact contacts;

public:
 // 添加联系人
 void addContact(const Contact& c) {
 contacts.push_back(c);
 std::cout << "添加成功!" << std::endl;
 }
 
 // 查找联系人(按姓名)
 Contact* findByName(const std::string& name) {
 for (auto& c : contacts) {
 if (c.getName() == name) {
 return &c;
 }
 }
 return nullptr;
 }
 
 // 删除联系人(按姓名)
 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 << "删除成功!" << std::endl;
 return true;
 }
 
 std::cout << "未找到联系人:" << name << std::endl;
 return false;
 }
 
 // 显示所有联系人
 void displayAll() const {
 if (contacts.empty()) {
 std::cout << "通讯录为空" << std::endl;
 return;
 }
 
 for (const auto& c : contacts) {
 c.display();
 }
 }
 
 // 保存到文件
 void saveToFile(const std::string& filename) const {
 std::ofstream file(filename);
 if (!file) {
 std::cerr << "无法打开文件" << std::endl;
 return;
 }
 
 for (const auto& c : contacts) {
 c.save(file);
 }
 
 file.close();
 std::cout << "保存成功!" << std::endl;
 }
 
 // 从文件加载
 void loadFromFile(const std::string& filename) {
 std::ifstream file(filename);
 if (!file) {
 std::cerr << "无法打开文件" << std::endl;
 return;
 }
 
 contacts.clear(); // 清空现有数据
 
 std::string line;
 while (file.peek() != EOF) {
 contacts.push_back(Contact::load(file));
 }
 
 file.close();
 std::cout << "加载成功!" << std::endl;
 }
};
逻辑代码 65 行(超过 40 行限制,仅展示)

输出:

TEXT 📖 仅展示
添加成功!
删除成功!
未找到联系人:
通讯录为空
保存成功!
加载成功!


4. 主菜单

(1) 4.1 菜单实现

CPP
void showMenu() {
### ▶ 示例 2:基础编程实践(难度⭐)

 std::cout << "\n===== 通讯录管理系统 =====" << std::endl;
 std::cout << "1. 添加联系人" << std::endl;
 std::cout << "2. 删除联系人" << std::endl;
 std::cout << "3. 查找联系人" << std::endl;
 std::cout << "4. 显示所有联系人" << std::endl;
 std::cout << "5. 保存" << std::endl;
 std::cout << "6. 加载" << std::endl;
 std::cout << "0. 退出" << std::endl;
 std::cout << "==========================" << std::endl;
 std::cout << "请选择:";
}

int main() {
 AddressBook book;
 int choice;
 
 do {
 showMenu();
 std::cin >> choice;
 
 switch (choice) {
 case 1: {
 std::string name, phone, email;
 std::cout << "姓名:";
 std::cin >> name;
 std::cout << "电话:";
 std::cin >> phone;
 std::cout << "邮箱:";
 std::cin >> email;
 book.addContact(Contact(name, phone, email));
 break;
 }
 case 2: {
 std::string name;
 std::cout << "姓名:";
 std::cin >> name;
 book.removeByName(name);
 break;
 }
 case 3: {
 std::string name;
 std::cout << "姓名:";
 std::cin >> name;
 Contact* c = book.findByName(name);
 if (c) {
 c->display();
 } else {
 std::cout << "未找到" << 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 << "再见!" << std::endl;
 break;
 default:
 std::cout << "无效选择" << std::endl;
 }
 } while (choice != 0);
 
 return 0;
}


5. 扩展建议

(1) 5.1 功能扩展

功能 难度
按电话查找
修改联系人 ⭐⭐
按姓名排序 ⭐⭐
导入/导出CSV ⭐⭐⭐
图形界面 ⭐⭐⭐⭐


6. ❓ 练习

(1) 基础练习(难度⭐)

给通讯录添加"按电话查找"功能。

(2) 进阶练习(难度⭐⭐)

给通讯录添加"修改联系人"功能。

(3) 挑战练习(难度⭐⭐⭐)

std::map 重构通讯录,提高查找效率。


▶ 示例 3:联系人结构体定义(难度⭐)

CPP
#include <iostream>
#include <string>

struct Contact {
    std::string name;
    std::string phone;
    std::string email;

    void display() const {
        std::cout << "姓名:" << name << std::endl;
        std::cout << "电话:" << phone << std::endl;
        std::cout << "邮箱:" << email << std::endl;
    }
};

int main() {
    Contact c1 = {"张三", "13800138000", "zhangsan@example.com"};
    Contact c2 = {"李四", "13900139000", "lisi@example.com"};

    c1.display();
    std::cout << "---" << std::endl;
    c2.display();

    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
姓名:
电话:
邮箱:
---

❓ 常见问题

Q 为什么用vector而不是数组?
A vector会自动扩容,不需要预先知道元素个数。数组的大小必须在编译时确定,而vector可以在运行时灵活增减。
Q 为什么联系人信息用结构体而不是多个数组?
A 结构体把相关数据打包在一起,逻辑更清晰。如果用多个数组,增删操作容易出错(名字删了但电话忘了删)。
Q 文件读写时需要注意什么?
A ①打开文件后要检查是否成功(is_open);②写入后要close();③读取时循环判断eof()或good()避免死循环;④异常处理确保文件正确关闭。

📖 小节

知识点 应用
面向对象 Contact和AddressBook类
STL vector存储联系人
文件操作 保存/加载
字符串处理 解析CSV

📝 作业

  1. 基础题 (Difficulty ⭐): 运行通讯录程序,添加3个联系人(姓名、电话、分组),查看显示效果。尝试用"编辑"功能修改其中一个联系人的信息。

  2. 进阶题 (Difficulty ⭐⭐): 给通讯录增加"收藏联系人"功能——在结构体里加一个 bool isFavorite 字段,在显示列表时把收藏联系人标为 [★]

  3. 挑战题 (Difficulty ⭐⭐⭐): 实现"模糊搜索"功能:用户输入关键字后,匹配所有姓名中含关键字的联系人并显示。如果输入为空则显示全部。支持不区分大小写匹配。


下一课:实战:简易数据库(#52)

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏