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

【读书笔记】《C++ Software Design》第二章:The Art of Building Abstractions

《C++ Software Design》第二章:The Art of Building Abstractions

本章详细探讨如何在 C++ 中构建高质量的抽象,包括行为预期、一致性、所有权管理和文档化。

Guideline 6: Adhere to the Expected Behavior of Abstractions

6.1 An Example of Violating Expectations

  • 示例场景:实现一个 Stack<T> 类时,提供 pop() 方法返回 T&,但在空栈调用时未抛出异常,而是返回未定义引用。

  • 问题:客户端无法预期 pop() 行为,违反直觉。

  • 解决方案

    • 改用 std::optional<T> 返回值,或抛出明确异常 std::underflow_error
    • 添加文档注释,明确表明函数的异常保证级别(noexcept 语义)。

6.2 The Liskov Substitution Principle

  • 定义:子类型必须能够替换父类型且不改变程序语义。

  • 具体实践

    • 前置条件:子类方法不应要求更严格输入。

    • 后置条件:子类方法输出应满足基类声明的约定。

    • 示例

      struct IShape { virtual double area() const = 0; };
      struct Rectangle : IShape { double area() const override; };
      struct Square : Rectangle { double side; double area() const override { return side * side; } };
      
    • 确保 Square 中不破坏 Rectangle 的预期行为,如修改 side 时边长一致性。

6.3 Criticism of the Liskov Substitution Principle

  • 争议:严格遵循 LSP 可能导致复杂的类型层次和过度抽象。
  • 作者观点:注重抽象的语义契约即可,不必机械化实施所有 LSP 条件。
  • 实践建议:编写契约测试(Contract Tests)验证继承层次的行为一致性。

6.4 The Need for Good and Meaningful Abstractions

  • 要点:抽象应贴合领域概念,避免陷入技术细节。

  • 示例:定义 Money 类型:

    class Money {long cents;
    public:explicit Money(long c): cents(c) {}double as_dollars() const { return cents / 100.0; }
    };
    
  • 好处:减少单元转换错误,增强类型安全性与可读性。

Guideline 7: Understand the Similarities Between Base Classes and Concepts

  • 继承与概念:两者均定义范畴与行为规范。

  • 运行时 vs 编译时:继承多态在运行时决议;概念约束在编译时检查。

  • 示例对比

    // 继承多态
    struct IFoo { virtual void foo() = 0; };
    void callFoo(IFoo* f) { f->foo(); }// 概念约束
    template<typename T>
    concept Fooable = requires(T a) { a.foo(); };
    void callFoo(Fooable auto& f) { f.foo(); }
    
  • 实践:对性能敏感场景优先使用概念,需动态扩展场景使用继承。

Guideline 8: Understand the Semantic Requirements of Overload Sets

8.1 The Power of Free Functions: A Compile-Time Abstraction Mechanism

  • 优势:支持对第三方类型扩展接口,无需修改原始类。

  • 示例

    struct Vector2D { float x, y; };
    inline float length(const Vector2D& v) { return std::hypot(v.x, v.y); }
    

8.2 The Problem of Free Functions: Expectations on the Behavior

  • 契约:自由函数应与成员函数语义一致。

  • 示例std::data(), std::size() 应返回与成员函数相同结果。

  • 实践

    • 在头文件中使用 using std::data; 保证 ADL 正常。
    • 文档明确输出和异常语义。

Guideline 9: Pay Attention to the Ownership of Abstractions

9.1 The Dependency Inversion Principle

  • 实践示例

    struct ILogger { virtual void log(std::string_view) = 0; };
    class ConsoleLogger : public ILogger { void log(std::string_view msg) override { std::cout<<msg; } };
    class App { std::unique_ptr<ILogger> logger; };
    

9.2 Dependency Inversion in a Plug-In Architecture

  • 步骤

    1. 定义插件接口 IPlugin
    2. 插件库导出 createPlugin() C 接口。
    3. 主程序用 dlopen/dlsym 加载并注册。
  • 代码

    extern "C" IPlugin* createPlugin();
    

9.3 Dependency Inversion via Templates

  • 示例

    template<typename Logger>
    class App { Logger logger; };
    

9.4 Dependency Inversion via Overload Sets

  • 示例

    void save(Data& d) { d.save(); }  // 自由函数调用 d.save()
    

9.5 DIP vs SRP

  • DIP:管理高低层依赖。
  • SRP:管理类职责。
  • 结合:通过细粒度接口同时满足二者。

Guideline 10: Consider Creating an Architectural Document

  • 目的:提升团队对系统全貌的理解。

  • 建议文档

    • 组件图(Component Diagram)
    • 类图(Class/Concept Diagram)
    • 序列图(Sequence Diagram)
    • 数据流图(Data Flow Diagram)
  • 工具:PlantUML、Mermaid。

  • 实践:将 UML 源文件纳入版本控制,与代码同步迭代。

http://www.xdnf.cn/news/15224.html

相关文章:

  • c++反射实现
  • Python ExcelWriter详解:从基础到高级的完整指南
  • 网络安全初级--搭建
  • python的婚纱影楼管理系统
  • Redis Geospatial 功能详解及多边形包含判断实现
  • SpringAI实现聊天记录保存到MySQL
  • 「日拱一码」025 机器学习——评价指标
  • Spring 框架中的设计模式:从实现到思想的深度解析
  • C++类模板继承部分知识及测试代码
  • 在 Android 库模块(AAR)中,BuildConfig 默认不会自动生成 VERSION_CODE 和 VERSION_NAME 字段
  • Linux之Zabbix分布式监控篇(一)
  • 云原生技术与应用-生产环境构建高可用Harbor私有镜像仓库
  • 网络通信模型对比:OSI与TCP/IP参考模型解析
  • BGP 路由优选属性(7)【MED】官方考试综合实验题【bgp】【acl】【ip-prefix】【route-policy】【icmp 环路】精讲
  • Frida绕过SSL Pinning (证书绑定)抓包;Frida注入;app无法抓包问题解决。
  • 哔哩哔哩第三方TV-BBLL最新版
  • Pyqt5 FlexRay
  • Redis事件机制
  • 特辑:Ubuntu,前世今生
  • Claude code在Windows上的配置流程
  • 基于Opencv的缺陷检测实战
  • cuDNN 的 IMPLICIT_GEMM 算法
  • 深入理解设计模式:建造者模式详解
  • Spring Boot 2.4+中bootstrap.yml加载顺序的源码深度解析
  • NLP:RNN文本生成案例分享
  • 常用控件QWidget
  • 第10讲——一元函数积分学的几何应用
  • 关于解决win 11安装mathtype报错的问题(toolbar.eql)
  • 计算机毕业设计ssm基于Web的高校食堂管理系统 基于SSM框架的大学智慧餐饮服务平台 JavaWeb校园食堂一站式订餐与供应链系统
  • 【kubernetes】--controller(DaemonSet)