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

Effective C++ 条款19: 设计class犹如设计type

Effective C++ 条款19:设计class犹如设计type


核心思想设计新的class时,应当像语言设计者设计内置类型一样慎重,考虑对象的创建、销毁、初始化、拷贝、类型转换等所有方面。

⚠️ 1. 类设计的关键问题域

对象生命周期管理

class ResourceHandle {
public:// 构造和析构:资源如何获取?如何释放?ResourceHandle(const std::string& resId);~ResourceHandle();  // 需要释放资源吗?private:Resource* resource_;
};

值语义与行为

class Rational {
public:// 拷贝操作:允许拷贝吗?浅拷贝还是深拷贝?Rational(const Rational& other);Rational& operator=(const Rational& other);// 类型转换:支持隐式转换吗?operator double() const;  // 危险:可能非预期转换
};

🚨 2. 解决方案:系统化设计方法

明确对象创建方式

class Session {
public:// 静态工厂方法:控制创建逻辑static Session createFromNetwork();static Session createFromFile(const std::string& path);// 禁用拷贝Session(const Session&) = delete;Session& operator=(const Session&) = delete;
private:Session();  // 私有构造
};

安全类型转换接口

class SafeRational {
public:// 显式转换函数(C++11)explicit operator double() const { return static_cast<double>(numerator)/denominator; }// 转换运算符替代方案double toDouble() const { /* ... */ }  // 更安全的显式转换
};

⚖️ 3. 关键设计原则与决策
设计维度关键问题推荐实践
对象创建/销毁构造函数参数?析构函数必要性?RAII模式管理资源
初始化/赋值区别构造函数与赋值操作符行为是否一致?确保一致性
值传递方式pass-by-value是否高效?小对象传值,大对象传const引用
操作符重载哪些操作符需要重载?仅重载符合直觉的操作符
类型转换控制是否允许隐式转换?使用explicit禁止非预期转换
成员访问权限哪些成员公开?哪些需要保护?最小化public接口
继承体系设计是否作为基类?虚函数如何设计?明确声明finaloverride
模板泛化可能性是否应设计为类模板?评估未来需求
标准库兼容性是否满足STL容器要求?提供必要的类型特征

成员函数设计规范

class Polynomial {
public:// 常量成员函数:不修改对象状态double evaluate(double x) const noexcept;// 异常安全保证void normalize() &;  // 仅限左值对象调用// 引用限定符(C++11)void process() &&;   // 仅限右值对象调用
};

继承体系设计规范

// 接口类设计
class Drawable {
public:virtual void draw() const = 0;virtual ~Drawable() = default;// 禁止拷贝(接口类通常不可拷贝)Drawable(const Drawable&) = delete;Drawable& operator=(const Drawable&) = delete;
};// 具体实现类
class Circle final : public Drawable {
public:void draw() const override;  // 明确重写// ...                         // 禁止进一步继承(final)
};

💡 关键原则总结

  1. 生命周期全周期设计
    • 构造/析构:资源获取即初始化(RAII)
    • 拷贝控制:明确=default/=delete拷贝操作
  2. 类型行为一致性
    • 操作符重载:行为需符合内置类型预期
    • 类型转换:优先使用explicit和命名转换函数
  3. 接口最小化原则
    • 成员函数:提供完备但最小的操作集合
    • 访问控制:严格限制private/protected
  4. 继承体系明确性
    • 基类:声明虚析构函数,明确抽象接口
    • 派生类:使用final/override明确意图

危险类设计示例

class AutoPtr {  // 已废弃的auto_ptr问题
public:// 问题1:允许从临时对象构造AutoPtr(AutoPtr& other);  // 非const引用// 问题2:转移所有权但不明确AutoPtr& operator=(AutoPtr& other);// 问题3:支持隐式指针转换operator void*() const;  // 可能导致误用
};

安全重构方案

// 解决方案:现代unique_ptr设计理念
template<typename T>
class UniquePtr {
public:// 明确所有权转移语义UniquePtr(UniquePtr&& other) noexcept;  // 移动构造UniquePtr& operator=(UniquePtr&& other) noexcept; // 移动赋值// 禁止拷贝UniquePtr(const UniquePtr&) = delete;UniquePtr& operator=(const UniquePtr&) = delete;// 显式bool转换(安全)explicit operator bool() const noexcept;// 明确资源释放接口void reset() noexcept;T* release() noexcept;
};
http://www.dtcms.com/a/313199.html

相关文章:

  • Python从入门到精通计划Day02: Python语法探秘:当现代艺术遇到古典音乐
  • 最小半径覆盖问题【C++解法+二分+扫描线】
  • 【CF】Day118——杂题 (随机哈希 / 思维 | 贪心 / DP | 位运算构造 | 状态压缩 + 建图 + 最短路 | 构造 | 贪心)
  • 使用纯Docker命令搭建多服务环境(Linux版)
  • Python篇---包
  • 在Ansys Mechanical中对磨损进行建模
  • 力扣经典算法篇-40-螺旋矩阵(方向遍历:方向数组+已访问元素集合)
  • 【ROS2】常用命令
  • 04.Redis 的多实例
  • 双八无碳小车设计【16张cad】三维图+设计说明书
  • 【C++ 初级工程师面试--5】inline内联函数特点 、和普通函数的区别、什么时候适合内联?
  • json-server 快速搭建本地 Mock 数据服务
  • Day23--回溯--39. 组合总和,40. 组合总和 II,131. 分割回文串
  • Android 之 MVC架构
  • 线段树学习笔记 - 摩尔投票问题
  • I2C基础
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
  • PHP现代化全栈开发:前后端分离与API架构实践
  • uni-app学习笔记01-项目初始化及相关文件
  • Go语言常量
  • 11.消息队列
  • 计算机视觉CS231n学习(2)
  • 从马武寨穿越关山
  • ICCV 2025 | EPD-Solver:西湖大学发布并行加速扩散采样算法
  • p5.js 用 beginGeometry () 和 endGeometry () 打造自定义 3D 模型
  • 控制建模matlab练习06:比例积分控制-②PI控制器
  • 达梦数据库联机备份和脱机备份的区别
  • Centos7 安装Python3.11
  • 【Linux系统编程】进程信号
  • leecode2958 最多K个重复元素的最长子数组