C++中为何频繁使用get/set函数?直接公开类成员变量与使用get/set函数的意义探讨
好问题!这绝对是面向对象编程入门阶段最容易困惑的问题之一——明明直接把成员变量设为public更省事,为啥还要多写一堆get/set函数?咱们先回应你的猜想,再拆解get/set的核心价值:
关于你猜想的“变量顺序错位”
这个理由其实不太成立。C++中,只要你不做一些非常规操作(比如强制把类对象转成结构体、直接操作内存偏移),调整类成员的顺序并不会影响外部直接访问public成员的代码——因为编译器是通过成员名字来定位的,不是靠内存位置。所以这个不是用get/set的核心原因。
get/set函数的真正意义
1. 数据校验与合法性控制
直接把marbles设为public,外部代码可以随便给它赋值:
thing t; t.marbles = -10; // 负数的弹珠?逻辑上不合理,但编译器不会拦你
但用setMarbles就能在赋值前加校验逻辑:
void setMarbles(int _marbles) { if (_marbles >= 0) { // 确保弹珠数量非负 marbles = _marbles; } else { throw std::invalid_argument("Marbles can't be negative!"); // 或者做其他错误处理 } }
这样就能保证类的状态始终合法,避免逻辑错误。
2. 隐藏实现细节,降低耦合
假设后来你发现用int存弹珠不够,想换成unsigned int,甚至想改成从其他成员计算得到的动态值(比如marbles = totalItems - usedItems)。如果用了get/set:
- 你只需要修改
setMarbles的参数类型,或者getMarbles的返回逻辑 - 所有调用
getMarbles()/setMarbles()的外部代码完全不用改
但如果是public成员,所有直接访问t.marbles的代码都要跟着改类型,甚至调整逻辑,维护成本会爆炸。
3. 灵活控制访问权限
有时候你希望某个变量是“只读”的——外部只能看,不能改。用get/set的话,只提供getMarbles,不写setMarbles就行:
class thing { public: int getMarbles() { return marbles; } // 只读 private: int marbles; // 只有类内部能修改marbles };
如果是public成员,要么全开放读写,要么完全私有,没有中间的“只读”选项。
4. 触发额外逻辑
比如你需要在弹珠数量变化时记录日志、更新UI,或者通知其他对象(观察者模式),这些逻辑都可以塞到setMarbles里:
void setMarbles(int _marbles) { if (marbles != _marbles) { marbles = _marbles; log("Marbles changed to: " + std::to_string(marbles)); ui->updateMarblesDisplay(marbles); notifyObservers(); } }
直接赋值的话,你得每次手动加这些代码,很容易遗漏,也不符合“单一职责”原则。
5. 支持懒加载/缓存
如果marbles的值需要从数据库、文件或者复杂计算中获取,getMarbles可以实现懒加载:
int getMarbles() { if (!marblesLoaded) { marbles = loadMarblesFromDB(); // 第一次访问才加载 marblesLoaded = true; } return marbles; }
外部代码完全感知不到这个加载过程,还是像调用普通函数一样用getMarbles(),非常方便。
总结
如果你的类只是一个纯粹的“数据容器”(比如没有任何逻辑的结构体),直接用public成员没问题。但如果你的类是有行为、需要维护状态合法性、未来可能迭代的“对象”,get/set函数是维护封装性、可扩展性和代码健壮性的关键——说白了,它给你的类留了足够的“后路”,不至于改个内部实现就要动所有外部代码。
内容的提问来源于stack exchange,提问作者sammonius

