重生之我在10天内卷赢C++ 项目实战篇

发布于:2025-08-04 ⋅ 阅读:(16) ⋅ 点赞:(0)

🚀 重生之我在10天内卷赢C++ 项目实战

导师寄语:恭喜你,完成了前面十天的冒险,我的“卷王”毕业生!过去的十天,我们从一行 Hello, World! 开始,一路披荆斩棘,征服了类、继承、多态、STL和智能指针、多进程多线程。你已经不再是那个面对黑框不知所措的小白了。今天,没有新的语法,只有实战!我们将把所有学过的“武功招式”融会贯通,打造一个完整、有用的项目——一个简易的学生信息管理系统。这不仅是对你学习成果的最终检验,更是你作为一名C++开发者,独立创造的开端!亮出你的键盘,让我们开始构建吧!

🎯 今日目标

  1. 综合运用前10天所学的所有核心知识点(类、继承、多态、STL、文件IO等)。
  2. 设计并实现一个多文件的C++项目。
  3. 学习使用 Makefile 来自动化编译我们的项目,告别手敲冗长的g++命令。
  4. 完成一个功能完善的学生信息管理系统,包括添加、显示、查找、删除和保存/加载数据的功能。
  5. 庆祝你成功“卷”赢C++,顺利毕业!

1. 项目构思:学生信息管理系统

我们要做的这个系统,虽然简单,但五脏俱全,任何复杂的大厦都是一砖一瓦搭起来的,不断在小项目上添砖加瓦,结合QT、网络编程、数据库等等知识,可以构建一个更加完整的项目。

核心功能需求:

  1. 添加学生:可以输入新学生的姓名、ID和成绩,并添加到系统中。
  2. 显示所有学生:将系统中所有学生的信息打印到屏幕上。
  3. 查找学生:根据学生ID快速找到并显示特定学生的信息。
  4. 删除学生:根据学生ID删除一个学生。
  5. 保存到文件:在程序退出时,将所有学生数据保存到一个文件中。
  6. 从文件加载:在程序启动时,自动从文件中加载之前保存的数据。

2. 面向对象设计 (OOD)

一个好的项目,从好的设计开始。我们来规划一下需要的“零件”(类)。

  • Student : 用来封装单个学生的所有信息。

    • 属性 (private): int id, std::string name, double score
    • 行为 (public): 构造函数、析构函数,以及一些获取信息的方法 (get_id, get_name等)。
  • StudentManager : 系统的“大脑”,负责管理所有的学生对象和业务逻辑。

    • 属性 (private): std::vector<Student> students,用一个vector来存储所有的学生对象。
    • 行为 (public): add_student(), display_all(), find_student(), delete_student(), save_to_file(), load_from_file()

3. 代码实现:分文件编写

我们把项目拆分成几个文件,让结构更清晰。

Student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <string>
#include <iostream>

class Student {
    // 友元,方便 StudentManager 直接访问私有成员进行文件读写
    friend class StudentManager;
    friend std::ostream& operator<<(std::ostream& os, const Student& s);

private:
    int id;
    std::string name;
    double score;

public:
    Student(int id, std::string name, double score);
    int get_id() const;
};

#endif

Student.cpp

#include "Student.h"

Student::Student(int id, std::string name, double score) 
    : id(id), name(name), score(score) {}

int Student::get_id() const {
    return id;
}

// 重载 << 运算符,方便打印学生信息
std::ostream& operator<<(std::ostream& os, const Student& s) {
    os << "ID: " << s.id << "\t姓名: " << s.name << "\t分数: " << s.score;
    return os;
}

StudentManager.h

#ifndef STUDENT_MANAGER_H
#define STUDENT_MANAGER_H

#include "Student.h"
#include <vector>
#include <string>

class StudentManager {
private:
    std::vector<Student> students;
    std::string filename; // 数据文件名
    int next_student_id;  // 用于自动生成学号

    void save_to_file();
    void load_from_file();

public:
    StudentManager(const std::string& fname);
    ~StudentManager(); // 析构函数中保存数据

    void add_student();
    void display_all() const;
    void find_student() const;
    void delete_student();
};

#endif

StudentManager.cpp (核心逻辑)

#include "StudentManager.h"
#include <iostream>
#include <fstream>   // 文件流
#include <algorithm> // for find_if
#include <limits>    // for numeric_limits

using namespace std;

StudentManager::StudentManager(const string& fname) : filename(fname), next_student_id(1) {
    load_from_file();
}

StudentManager::~StudentManager() {
    save_to_file();
}

void StudentManager::load_from_file() {
    ifstream infile(filename);
    if (!infile) {
        cout << "未找到数据文件,将创建一个新文件。" << endl;
        return;
    }

    int id;
    string name;
    double score;
    int max_id = 0;
    while (infile >> id >> name >> score) {
        students.emplace_back(id, name, score); // emplace_back比push_back更高效
        if (id > max_id) {
            max_id = id;
        }
    }
    next_student_id = max_id + 1; // 确保新学号不重复
    cout << "成功加载 " << students.size() << " 条学生数据。" << endl;
}

void StudentManager::save_to_file() {
    ofstream outfile(filename);
    if (!outfile) {
        cerr << "错误:无法打开文件进行写入!" << endl;
        return;
    }
    for (const auto& s : students) {
        // 直接访问私有成员,因为Student类授权了友元
        outfile << s.id << " " << s.name << " " << s.score << endl;
    }
    cout << "数据已成功保存到 " << filename << endl;
}

void StudentManager::add_student() {
    string name;
    double score;
    cout << "请输入学生姓名: ";
    cin >> name;
    cout << "请输入学生分数: ";
    cin >> score;

    students.emplace_back(next_student_id, name, score);
    cout << "添加成功!新学生ID为: " << next_student_id << endl;
    next_student_id++;
}

void StudentManager::display_all() const {
    if (students.empty()) {
        cout << "系统中没有学生信息。" << endl;
        return;
    }
    cout << "\n--- 所有学生信息 ---" << endl;
    for (const auto& s : students) {
        cout << s << endl;
    }
    cout << "----------------------" << endl;
}

void StudentManager::find_student() const {
    int id;
    cout << "请输入要查找的学生ID: ";
    cin >> id;

    auto it = find_if(students.begin(), students.end(), [id](const Student& s) {
        return s.get_id() == id;
    });

    if (it != students.end()) {
        cout << "找到了学生: " << *it << endl;
    } else {
        cout << "未找到ID为 " << id << " 的学生。" << endl;
    }
}

void StudentManager::delete_student() {
    int id;
    cout << "请输入要删除的学生ID: ";
    cin >> id;

    auto it = find_if(students.begin(), students.end(), [id](const Student& s) {
        return s.get_id() == id;
    });

    if (it != students.end()) {
        students.erase(it);
        cout << "ID为 " << id << " 的学生已成功删除。" << endl;
    } else {
        cout << "未找到ID为 " << id << " 的学生,删除失败。" << endl;
    }
}

main.cpp (用户交互界面)

#include "StudentManager.h"
#include <iostream>
#include <limits>

using namespace std;

void show_menu() {
    cout << "\n===== 学生信息管理系统 =====" << endl;
    cout << "1. 添加学生" << endl;
    cout << "2. 显示所有学生" << endl;
    cout << "3. 查找学生" << endl;
    cout << "4. 删除学生" << endl;
    cout << "0. 退出系统" << endl;
    cout << "===========================" << endl;
    cout << "请输入您的选择: ";
}

int main() {
    StudentManager manager("students.txt");
    int choice;

    while (true) {
        show_menu();
        cin >> choice;

        if (cin.fail()) {
            cout << "无效输入,请输入数字!" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            continue;
        }

        switch (choice) {
            case 1: manager.add_student(); break;
            case 2: manager.display_all(); break;
            case 3: manager.find_student(); break;
            case 4: manager.delete_student(); break;
            case 0: cout << "感谢使用,系统退出。" << endl; return 0;
            default: cout << "无效选择,请重新输入!" << endl; break;
        }
    }

    return 0;
}

4. 使用 Makefile 实现自动化编译

现在我们有4个.cpp文件,如果每次都手敲 g++ main.cpp Student.cpp StudentManager.cpp -o student_system,也太麻烦了。Makefile 就是来解决这个问题的!本文就不细讲makefile文件的编写,发挥你的自学能力,去了解这个可以在linux中增加生产力的方法吧!!

在你的项目目录下,创建一个名为 Makefile 的文件(没有后缀名)。

文件: Makefile

# 编译器
CXX = g++
# 编译选项 -std=c++11 开启C++11标准支持, -Wall 显示所有警告
CXXFLAGS = -std=c++11 -Wall

# 目标文件名
TARGET = student_system

# 所有的源文件 (.cpp)
SRCS = main.cpp Student.cpp StudentManager.cpp
# 根据源文件自动生成所有的目标文件 (.o)
OBJS = $(SRCS:.cpp=.o)

# 默认规则:链接所有.o文件生成最终的可执行文件
all: $(TARGET)

$(TARGET): $(OBJS)
	$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)

# 通用规则:如何从 .cpp 文件生成 .o 文件
%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

# 清理规则:删除所有生成的文件
clean:
	rm -f $(OBJS) $(TARGET)

Makefile 使用方法:

  • 编译项目:在终端输入 make,它会自动执行 all 规则。
  • 清理项目:输入 make clean,它会删除所有编译生成的文件。

现在,管理你的项目是不是瞬间变得专业和高效了?


5. 未来之路

🎉🎉🎉 恭喜你,你毕业了! 🎉🎉🎉

回首这10天,我们从一个对C++一无所知的“小白”,成长为能够独立设计、编写、编译一个完整项目的开发者。你掌握了:

  • 基础语法Linux/Vim/g++ 开发环境。
  • 面向对象 的核心:封装、继承、多态。
  • 内存管理:从手动new/delete到现代的智能指针
  • STL 的强大威力,用 vector, map, algorithm 极大地提升了效率。
  • 项目工程化:用 Makefile 管理多文件项目。

你手中的“学生信息管理系统”就是你这10天努力的最好证明!它虽然简单,但它包含了现代C++开发中几乎所有的核心要素。

未来之路在何方?

  • 深入STL:探索更多容器(set, deque)和更复杂的算法。
  • 学习C++11/14/17/20新特性move语义、并发编程(std::thread)、文件系统库等。
  • 图形界面编程:学习Qt等库,为你的程序穿上华丽的外衣。
  • 网络编程:学习socket,让你的程序能与世界对话。
  • 参与开源项目:在GitHub上找到你感兴趣的项目,从读代码、提issue开始,贡献你的力量。

“重生之我在10天内卷赢C++” 的旅程到此结束,但你作为一名C++开发者的传奇故事,才刚刚开始。保持好奇,不断学习,勇于实践。世界在你手中,去创造吧!

点个赞和关注,更多知识包你进步,谢谢!!!你的支持就是我更新的最大动力


网站公告

今日签到

点亮在社区的每一天
去签到