《 C++ 零基础入门教程》第3章:结构体与类 —— 用面向对象组织代码

✅ 本篇目标:

  • 理解 结构体(struct)类(class)
  • 掌握 封装、构造函数、成员函数
  • 升级你的"学生成绩管理系统",用 OOP 重构
  • 理解 C++ 中 structclass 的区别
    🕒 建议学习时间: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 思维 将现实事物抽象为"对象"

✅ 下一步建议

  1. 思考 :如果学生数量不确定,如何避免 MAX 限制?
    → 答案:使用 std::vector<Student>(第 4 篇)
  2. 尝试 :给 GradeSystem 添加"按姓名查找"功能
  3. 预习:什么是"析构函数"?对象销毁时会发生什么?

相关推荐
向量引擎2 小时前
复刻“疯狂的鸽子”?用Python调用Sora2与Gemini-3-Pro实现全自动热点视频流水线(附源码解析)
开发语言·人工智能·python·gpt·ai·ai编程·api调用
郑泰科技2 小时前
快速地图匹配(FMM)的开源工具与代码示例
c++·windows·python·交通物流
CoderCodingNo2 小时前
【GESP】C++五级练习(贪心思想考点) luogu-P1115 最大子段和
开发语言·c++·算法
Q741_1472 小时前
C++ 队列 宽度优先搜索 BFS 力扣 429. N 叉树的层序遍历 每日一题
c++·算法·leetcode·bfs·宽度优先
a程序小傲2 小时前
得物Java面试被问:边缘计算的数据同步和计算卸载
java·开发语言·数据库·后端·面试·golang·边缘计算
lly2024062 小时前
PHP 运算符
开发语言
txinyu的博客2 小时前
make_shraed & make_unique 替代了new ? 什么场景使用new
开发语言·c++·算法
不会c嘎嘎2 小时前
QT中的常用控件(五)
服务器·开发语言·qt
你不是我我2 小时前
【Java 开发日记】我们来说一下无锁队列 Disruptor 的原理
java·开发语言