public / private / protected
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 17 篇。类里的数据默认不让外人碰,碰不碰得看访问权限:public谁都能碰,private只有自己人,protected给子类留后门。访问控制是"封装"这个口号落地的语法机制,也是 C 的结构体给不了的纪律。
本文要回答的问题
public/private/protected各自管什么?- 封装到底图什么?数据私有什么实际好处?
- 类里怎么切分这几段权限?
一、三档权限,一图说清
class BankAccount {
private:
double balance_ = 0; // 私有:只有本类成员能碰
protected:
int account_no_; // 保护:本类 + 子类能碰
public:
void deposit(double m) { // 公开:谁都能调
if (m > 0) balance_ += m;
}
double balance() const { return balance_; }
};| 关键字 | 谁能访问 | 典型用途 |
|---|---|---|
public | 任何地方 | 对外接口:方法、构造、析构 |
protected | 本类 + 派生类 | 给继承留的后门(第 26 篇用上) |
private | 仅本类(含友元) | 内部数据、内部实现 |
类里可以写多段,按 public: / private: / protected: 标签切分,顺序、次数随意。默认(开头没写标签的那段)是 private——class 的默认值,上一篇文章提过,这里记住:类的数据默认就是私有的,你要公开得显式写 public:。
二、封装图什么:数据私有的实际好处
把 balance_ 设为 private,外人只能通过 deposit() / balance() 操作它。好处三条:
- 合法性校验:
deposit里拦住了负数存款——如果余额直接公开,谁能保证所有人先检查再赋值? - 行为可控:
balance()只读不改,读不坏数据;deposit是所有改动的唯一入口,想加日志、加校验只改一处; - 内部可换:哪天把
double balance_换成int cents_(用分存储避免浮点误差),外部代码一行不用改,接口没变。
第 3 条是封装的精髓:外部代码依赖的是接口,不是内部表示。C 里想做到这点只能靠自律——"约定 _ 开头的别碰",编译器不拦。C++ 是编译器替你强制。
BankAccount acc;
acc.deposit(100);
acc.deposit(-50); // 被拦:deposit 里校验 m > 0
// acc.balance_ = 99999; // 错误:balance_ 是 private,编译不过
std::cout << acc.balance(); // 100,只能通过接口读三、class 默认 private,struct 默认 public
class A { int x; }; // x 是 private
struct B { int x; }; // x 是 public同一件事,class 和 struct 的默认立场相反。这就是上一篇说的"唯一区别"。写代码时:
- 想表达"这是数据聚合,随便读"→
struct,省得每个成员写public:; - 想表达"这是有状态、有行为的东西"→
class,数据默认收起来。
四、和 C 对比
| 对比项 | C | C++ |
|---|---|---|
| 访问控制 | 无,全靠约定 | 语言强制三档 |
| 私有数据 | 不存在的概念 | private: 编译器把关 |
| 封装的保障 | 靠程序员自觉 | 靠编译器报错 |
| 接口与实现的分离 | 手动管理 | private 自动隔离 |
| 头文件里暴露 | 结构体成员全可见 | 私有成员也可见(编译期),但不可访问 |
最后一条值得说:C++ 的 private 成员在头文件里看得到、摸不着——你读代码能看到 balance_ 存在,但代码里写 acc.balance_ 编译直接报错。这叫"编译期可见、访问期禁止",正因如此头文件改了私有成员,所有 include 它的文件都要重编,这也是 C++ 编译慢的原因之一。
五、与本站主线衔接
protected真正发挥作用是在继承里,见 继承基础;friend(友元)可以突破private的限制,是封装的一个例外口子,见 友元;- 私有成员在对象布局中如何排布、
private与类布局的关系,见专家层对象内存布局; - 下一篇进入对象的出生:构造函数与初始化列表。
一句话总结
public 谁都能碰(对外接口)、private 只有本类能碰(内部数据)、protected 给子类留后门,class 默认私有而 struct 默认公有;封装的价值是把改动限制在类内部、把合法性校验收进唯一入口,编译器替你强制 C 只能靠自觉的纪律。
上一篇:类定义与成员 下一篇:构造函数与初始化列表