✅ 本篇目标:
- 理解 结构体(struct) 与 类(class)
- 掌握 封装、构造函数、成员函数
- 升级你的"学生成绩管理系统",用 OOP 重构
- 理解 C++ 中
struct和class的区别
🕒 建议学习时间:3--4 小时|可分多次完成💡 即使你是 Java 开发者,也请认真看 ------ C++ 的对象模型更底层、更灵活!
📘 C++ 零基础入门教程(第 3 篇)
结构体与类 ------ 用面向对象组织代码
第一步:为什么需要"结构体"?
在第 2 篇的学生成绩系统中,我们用了两个数组:
cpp
string names[3];
double scores[3];
但 姓名和成绩本质上属于同一个学生,应该打包在一起!
▶ 问题:
- 数据分散,容易出错(比如名字和分数对不上)
- 无法表达"学生"这个概念
✅ 解决方案:结构体(struct)
第二步:定义结构体(struct)
结构体是一种自定义数据类型,可以包含多个不同类型的成员。
cpp
#include <iostream>
#include <string>
using namespace std;
// 定义一个 Student 结构体
struct Student {
string name;
double score;
};
int main() {
// 创建一个 Student 变量
Student s1;
s1.name = "Alice";
s1.score = 95.5;
cout << s1.name << " 的成绩是 " << s1.score << endl;
// 也可以初始化时赋值(C++11 起支持)
Student s2{"Bob", 88.0};
cout << s2.name << " 的成绩是 " << s2.score << endl;
return 0;
}
✅ 输出:
Alice 的成绩是 95.5
Bob 的成绩是 88
🔑 关键点:
struct Student { ... };定义了一个新类型- 使用
.操作符访问成员(如s1.name)
第三步:数组 of 结构体 ------ 管理多个学生
现在,我们可以用一个数组存储所有学生:
cpp
const int N = 2;
Student students[N] = {
{"Alice", 95.5},
{"Bob", 88.0}
};
// 遍历
for (int i = 0; i < N; i++) {
cout << students[i].name << ": " << students[i].score << endl;
}
💡 这比两个独立数组清晰多了!
第四步:给结构体添加"行为" ------ 成员函数
结构体不仅能存数据,还能包含函数(称为"成员函数"):
cpp
struct Student {
string name;
double score;
// 成员函数:打印信息
void print() const {
cout << name << ": " << score << endl;
}
// 成员函数:判断是否及格
bool isPassing() const {
return score >= 60;
}
};
使用示例:
cpp
Student s{"Charlie", 55};
s.print(); // Charlie: 55
if (!s.isPassing()) {
cout << s.name << " 没有及格!" << endl;
}
⚠️ 注意
const:
- 在函数末尾加
const表示"此函数不修改对象"- 这样
const Student对象也能调用它
第五步:构造函数(Constructor)------ 初始化对象
每次手动赋值很麻烦。我们可以用 构造函数 自动初始化:
cpp
struct Student {
string name;
double score;
// 构造函数(无返回值,名字和 struct 相同)
Student(string n, double s) {
name = n;
score = s;
}
// 默认构造函数(可选)
Student() {
name = "未知";
score = 0.0;
}
void print() const {
cout << name << ": " << score << endl;
}
};
// 使用
Student s1("David", 92.0); // 调用带参构造
Student s2; // 调用默认构造
✅ 构造函数让你的对象"生来就完整"。
第六步:从 struct 到 class ------ 封装的力量
C++ 中还有 class 关键字,它和 struct 几乎一样,只有一个默认区别:
| 默认访问权限 | |
|---|---|
struct |
public |
class |
private |
▶ 什么是"访问权限"?
public:外部可以访问private:只有类内部函数能访问
为什么需要 private?
为了 封装(Encapsulation) ------ 隐藏内部细节,只暴露安全接口。
示例:用 class 重写 Student
cpp
class Student {
private:
string name;
double score;
public:
// 构造函数(必须 public 才能被外部调用)
Student(string n, double s) : name(n), score(s) {}
// 提供公共接口(getter)
string getName() const { return name; }
double getScore() const { return score; }
// 提供安全的 setter(可加校验)
void setScore(double s) {
if (s >= 0 && s <= 100) {
score = s;
} else {
cout << "成绩无效!" << endl;
}
}
void print() const {
cout << name << ": " << score << endl;
}
};
使用:
cpp
Student s("Eva", 105); // 构造时无法校验(改进见下文)
s.setScore(105); // 输出:成绩无效!
s.print(); // Eva: 100(假设初始为100)
💡 最佳实践:
- 数据成员设为
private- 通过
public函数提供受控访问
第七步:升级项目 ------ OOP 版学生成绩管理系统
我们将用 class 重构第 2 篇的系统,让它更健壮、可扩展。
✅ 功能增强:
- 支持动态添加学生(先固定数量)
- 自动计算平均分、最高分
- 数据封装,防止非法修改
完整代码(student_oop.cpp):
cpp
#include <iostream>
#include <string>
#include <vector> // 先用固定数组,第4篇改 vector
using namespace std;
class Student {
private:
string name;
double score;
public:
Student(string n, double s) : name(n), score(s) {}
string getName() const { return name; }
double getScore() const { return score; }
void print() const {
cout << name << "\t" << score << endl;
}
};
class GradeSystem {
private:
static const int MAX = 10;
Student students[MAX];
int count = 0;
public:
void addStudent(const string& name, double score) {
if (count < MAX) {
students[count] = Student(name, score);
count++;
} else {
cout << "班级已满!" << endl;
}
}
void printAll() const {
cout << "\n--- 成绩列表 ---\n";
cout << "姓名\t成绩\n";
for (int i = 0; i < count; i++) {
students[i].print();
}
}
double getAverage() const {
if (count == 0) return 0;
double sum = 0;
for (int i = 0; i < count; i++) {
sum += students[i].getScore();
}
return sum / count;
}
Student getTopStudent() const {
if (count == 0) return Student("无", 0);
Student top = students[0];
for (int i = 1; i < count; i++) {
if (students[i].getScore() > top.getScore()) {
top = students[i];
}
}
return top;
}
};
int main() {
GradeSystem system;
system.addStudent("Alice", 95);
system.addStudent("Bob", 88);
system.addStudent("Charlie", 92);
system.printAll();
cout << "\n平均分: " << system.getAverage() << endl;
cout << "最高分: ";
system.getTopStudent().print();
return 0;
}
▶ 编译运行:
bash
g++ student_oop.cpp -o grade
./grade
✅ 输出:
--- 成绩列表 ---
姓名 成绩
Alice 95
Bob 88
Charlie 92
平均分: 91.6667
最高分: Alice 95
🎉 你已经用 面向对象思想 构建了一个小型系统!
📌 本篇小结:你已掌握
| 概念 | 说明 |
|---|---|
| struct | 自定义数据类型,成员默认 public |
| class | 更安全的自定义类型,成员默认 private |
| 封装 | 用 private 隐藏数据,用 public 函数提供接口 |
| 构造函数 | 初始化对象,确保状态有效 |
| 成员函数 | 与数据紧密关联的行为 |
| OOP 思维 | 将现实事物抽象为"对象" |
✅ 下一步建议
- 思考 :如果学生数量不确定,如何避免
MAX限制?
→ 答案:使用std::vector<Student>(第 4 篇) - 尝试 :给
GradeSystem添加"按姓名查找"功能 - 预习:什么是"析构函数"?对象销毁时会发生什么?