当前位置: 首页 > news >正文

Effective C++ 条款22: 将成员变量声明为private

Effective C++ 条款22:将成员变量声明为private


核心思想始终将成员变量声明为private,通过函数接口控制访问,提供封装弹性、精确访问控制和一致性维护点。

⚠️ 1. 公开成员的致命缺陷

数据一致性破坏

class AccessPoint {
public:int x;  // 公开成员int y;double signalStrength;
};AccessPoint ap;
ap.x = 100;   // 直接修改
ap.y = 200;   // 无任何校验
// 坐标改变但signalStrength未更新 → 数据不一致

接口僵化问题

class Thermostat {
public:double currentTemp;  // 公开成员double targetTemp;
};// 客户端代码直接访问成员
if (thermostat.currentTemp < thermostat.targetTemp) {startHeating();
}// 需求变更:温度单位转换 → 必须修改所有客户端代码

🚨 2. 解决方案:严格private封装

受控访问接口

class SecureThermostat {
public:// 设置温度带校验void setTargetTemp(double temp) {if (temp < MIN_TEMP || temp > MAX_TEMP) throw InvalidTemp();targetTemp_ = temp;updateSystemState();}// 获取温度带单位转换double getCurrentTempCelsius() const { return currentTemp_; }double getCurrentTempFahrenheit() const {return (currentTemp_ * 9/5) + 32;}private:double currentTemp_;   // 私有成员double targetTemp_;void updateSystemState() { /* 状态同步逻辑 */ }
};

⚖️ 3. 封装优势与访问控制
封装级别访问控制可维护性弹性
public完全开放脆弱(直接耦合)零(修改破坏客户端)
protected派生类可见中度脆弱(影响派生类)低(修改影响继承体系)
private仅类内和友元可见强健(接口隔离)高(内部可自由修改)

封装性带来的核心优势

  1. 访问精确控制

    • 只读访问:仅提供const getter
    const std::string& getName() const { return name_; }
    
    • 条件写访问:带校验的setter
    void setAge(int age) {if (age < 0) throw InvalidAge();age_ = age;
    }
    
  2. 实现弹性

    class DataMonitor {
    public:// 接口保持不变int getValue() const { // 可无缝切换实现return useCache_ ? cachedValue_ : readHardware();}
    private:bool useCache_ = false;int cachedValue_;int readHardware() const;
    };
    
  3. 不变式维护

    class Account {
    public:void deposit(double amount) {if (amount <= 0) throw InvalidAmount();balance_ += amount;logTransaction();  // 自动记录}
    private:double balance_ = 0;void logTransaction();
    };
    

💡 关键原则总结

  1. 绝对封装原则
    • 所有数据成员必须private
    • 禁用public/protected数据成员
  2. 访问接口最小化
    • 提供必要getter/setter
    • 避免暴露实现细节
  3. 一致性维护点
    • 在setter中执行校验
    • 在getter中执行计算/转换
  4. protected的伪封装性
    • protected成员 ≈ public(对派生类)
    • 修改protected成员影响所有派生类

危险设计重现

class Config {
public:// 公共数据成员std::string serverIP;int port;bool useEncryption;
};// 客户端代码
Config cfg;
cfg.serverIP = "192.168.1.1";
cfg.port = 8080;
cfg.useEncryption = "true";  // 错误!类型不匹配但编译通过

安全重构方案

class SecureConfig {
public:// 安全设置接口void setServerIP(const std::string& ip) {if (!isValidIP(ip)) throw InvalidIP();serverIP_ = ip;}void setPort(int port) {if (port < 1 || port > 65535) throw InvalidPort();port_ = port;}void setEncryption(bool enable) {useEncryption_ = enable;updateSecurityContext();}// 只读访问const std::string& getServerIP() const { return serverIP_; }int getPort() const noexcept { return port_; }bool encryptionEnabled() const { return useEncryption_; }private:std::string serverIP_;int port_ = 80;  // 默认值bool useEncryption_ = false;
};// 使用示例
SecureConfig cfg;
cfg.setPort(8080);  // 安全设置
// cfg.setEncryption("true");  // 编译错误!类型安全
http://www.dtcms.com/a/315038.html

相关文章:

  • Pixel 4D 3.4.4.0 | 支持丰富的壁纸资源,高清画质,高度的个性化设置能力,智能推荐功能
  • Ubuntu 下 MySQL 离线部署教学(含手动步骤与一键脚本)
  • 力扣面试150题--加一
  • ZCC1004E-120V 3A 零功耗使能异步降压电源芯片
  • 人工智能之数学基础:条件概率及其应用
  • JS中的Set和WeakSet联系与区别
  • 数据结构---配置网络步骤、单向链表额外应用
  • 【Linux】Linux 操作系统 - 33 , 线程(二) 线程互斥和同步 , 带你对线程使用深刻理解 !
  • 《Python 实用项目与工具制作指南》· 2.2 变量
  • JVM调优工具详解
  • 把“距离过近”的节点(或端点)合并成一个,避免重复。机器学习 python
  • web:ts元组
  • 【RH124知识点问答题】第8章 监控和管理 Linux 进程
  • Bean的生命周期和循环依赖问题的解决
  • 防火墙认证用户部署
  • 开发规范(一)移动端
  • 多线程(一)
  • 【C#】操作Execl和Word文件-1
  • 子词分词器(Byte Pair Encoding + WordPiece)
  • 如何给Word和WPS文档添加密码或取消密码
  • 【Java】使用FreeMarker来实现Word自定义导出
  • 反转字符串中的元音字母:Swift 双指针一步到位
  • EXPLAIN工具:查询执行计划分析与索引诊断
  • 【数据结构】排序(sort) -- 插入排序
  • 如何设置端口映射?防火墙/路由器/纯软件工具多种常用方案步骤,确保任意内网ip端口映射公网访问到
  • 《汇编语言:基于X86处理器》第11章 复习题和练习
  • RocketMQ与Kafka 消费者组的‌重平衡操作消息顺序性对比
  • Hadoop MapReduce 3.3.4 讲解~
  • Linux系统编程-文件操作(黑马笔记)
  • 基于Springboot+Mybatis+thymeleaf的个人博客系统的设计与实现