🚀 重生之我在10天内卷赢C++ 项目实战
导师寄语:恭喜你,完成了前面十天的冒险,我的“卷王”毕业生!过去的十天,我们从一行
Hello, World!
开始,一路披荆斩棘,征服了类、继承、多态、STL和智能指针、多进程多线程。你已经不再是那个面对黑框不知所措的小白了。今天,没有新的语法,只有实战!我们将把所有学过的“武功招式”融会贯通,打造一个完整、有用的项目——一个简易的学生信息管理系统。这不仅是对你学习成果的最终检验,更是你作为一名C++开发者,独立创造的开端!亮出你的键盘,让我们开始构建吧!
🎯 今日目标
- 综合运用前10天所学的所有核心知识点(类、继承、多态、STL、文件IO等)。
- 设计并实现一个多文件的C++项目。
- 学习使用
Makefile
来自动化编译我们的项目,告别手敲冗长的g++
命令。 - 完成一个功能完善的学生信息管理系统,包括添加、显示、查找、删除和保存/加载数据的功能。
- 庆祝你成功“卷”赢C++,顺利毕业!
1. 项目构思:学生信息管理系统
我们要做的这个系统,虽然简单,但五脏俱全,任何复杂的大厦都是一砖一瓦搭起来的,不断在小项目上添砖加瓦,结合QT、网络编程、数据库等等知识,可以构建一个更加完整的项目。
核心功能需求:
- 添加学生:可以输入新学生的姓名、ID和成绩,并添加到系统中。
- 显示所有学生:将系统中所有学生的信息打印到屏幕上。
- 查找学生:根据学生ID快速找到并显示特定学生的信息。
- 删除学生:根据学生ID删除一个学生。
- 保存到文件:在程序退出时,将所有学生数据保存到一个文件中。
- 从文件加载:在程序启动时,自动从文件中加载之前保存的数据。
2. 面向对象设计 (OOD)
一个好的项目,从好的设计开始。我们来规划一下需要的“零件”(类)。
Student
类: 用来封装单个学生的所有信息。- 属性 (private):
int id
,std::string name
,double score
。 - 行为 (public): 构造函数、析构函数,以及一些获取信息的方法 (
get_id
,get_name
等)。
- 属性 (private):
StudentManager
类: 系统的“大脑”,负责管理所有的学生对象和业务逻辑。- 属性 (private):
std::vector<Student> students
,用一个vector
来存储所有的学生对象。 - 行为 (public):
add_student()
,display_all()
,find_student()
,delete_student()
,save_to_file()
,load_from_file()
。
- 属性 (private):
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++开发者的传奇故事,才刚刚开始。保持好奇,不断学习,勇于实践。世界在你手中,去创造吧!
点个赞和关注,更多知识包你进步,谢谢!!!你的支持就是我更新的最大动力