③ 面向对象程序设计 — 第 1 课
private,只留 public 方法。const,同名参数用 this->。面向对象说的三件事,先用一张表建立印象:
| 特性 | 一句话 | 生活例子 |
|---|---|---|
| 封装 Encapsulation | 数据和操作打包,细节藏起来 | 自动售货机:投币按按钮,内部结构看不到 |
| 继承 Inheritance | 子类复用父类 | 猫和狗都是动物 |
| 多态 Polymorphism | 同一句话,不同对象做不同的事 | 同样喊“叫”,猫喵、狗汪 |
这一课只管第一行。判断有没有做到封装,看一个标准:外面能不能绕过你的检查,直接把数据改坏。
封装的第一步是控制访问。C++ 用三个关键字决定「谁能进来」:
class Student {
private: // 私有:只有类内函数能碰
string name;
int score;
public: // 公有:外面可以调用
Student(string n, int s) : name(n), score(s) {}
};
| 关键字 | 谁能访问 | 什么时候用 |
|---|---|---|
private | 只有类内成员函数 | 数据成员(默认!) |
public | 谁都可以 | 接口:构造函数、方法 |
protected | 自己 + 子类 | 留给继承用(下一课) |
struct 默认 public,class 默认 private。写 class 时数据成员习惯放 private。
藏起来不是为了神秘,是为了让所有修改都过一个关口。
如果不藏:s.score = -100; 也能写进去,明显不合理。藏起来后,所有修改必须经过 setScore,可以在里面做检查:
class Student {
string name;
int score; // private:外面改不了
public:
Student(string n, int s) : name(n) {
setScore(s); // 构造时也走检查
}
void setScore(int s) { // 唯一修改入口
if (s < 0) s = 0; // 太低了,拉回 0
if (s > 100) s = 100; // 太高了,拉回 100
score = s;
}
int getScore() const { return score; } // 只读,不能改
};
这就是封装的精髓:数据 private + 方法 public + 入口校验。以后数据出问题,只需要查一个地方。
this 指针 —— 「我自己」参数名和成员名一样时,光写 score = score 就是自己赋自己。用 this-> 区分:
void setScore(int score) {
this->score = score; // 左边是成员变量,右边是参数
}
this 是指向当前对象的指针,this->score 就是「我这个对象的 score」。
const 成员函数 —— 保证不改int getScore() const { return score; } // const 在括号后面
意思是:这个函数保证不修改对象。好处:const 对象也只能调用 const 方法,编译器帮你检查。养成习惯:只读函数都加 const。
把访问权限、构造函数、const 方法拼在一起,就是一个能用的类:
#include <iostream>
#include <string>
using namespace std;
class Student {
string name;
int scores[3]; // 三科成绩
public:
Student(string n, int a, int b, int c) : name(n) {
scores[0] = a;
scores[1] = b;
scores[2] = c;
}
string getName() const { return name; }
int total() const { return scores[0] + scores[1] + scores[2]; }
double avg() const { return total() / 3.0; }
};
int main() {
Student s("Alice", 95, 87, 92);
cout << s.getName() << " " << s.total() << " " << s.avg() << endl;
return 0;
}
三个方法都是 const,因为它们只读不写。外面拿不到 scores,只能通过 total()、avg() 要结果——这就是「数据藏起来,接口露出去」。
class 默认 private,struct 默认 public。把数据写在 class 开头又忘了 private:,其实是私有的;反过来在 struct 里忘写,其实是公有的。setScore(s),不是直接 score = s。直接赋值等于把校验口开在了旁边。setScore 里只有 score = s;,没有范围检查,那和 public 数据没区别。const:一只读函数不加 const,const 对象调用它时会编译报错;而且这会逼着你把对象改成非 const。this->:void setScore(int score) { score = score; } 改的是参数,成员一点没动,编译器还不会报错。this->score = score 中,左边的 this->score 是什么?private 一个 double balance(余额)deposit(double m):存款,余额增加withdraw(double m):取款,余额不够时返回 false 且不扣钱getBalance() const:返回余额money.txt,下次启动读回来(用上 0014 的文件读写)写完按这个顺序自查:
balance 是不是 private?如果是 public,先把门关上再谈别的。balance 赋了值?withdraw 里,判断余额够不够是不是在扣钱之前?false,并且真的没有改动 balance?getBalance 后面有没有 const?private 只有类内能碰;class 默认 private,struct 默认 public。this-> 区分成员和参数;只读函数加 const。protected 数据、构造为什么总是先父后子。private 到了下一课会有一个专门的开门口令:protected。