具体描述
使用现代C 编写可维护、可扩展和持久的软件。对于每一个对好的C 代码感兴趣的开发人员、软件架构师或团队领导来说,这本书都是必须的,因此也想节省开发成本。如果你想自学编写整洁C 代码,本书正是你所需要的。编写它是为了帮助所有级别的C 开发人员,并通过示例展示如何编写可理解的、灵活的、可维护的和高效的C 代码。即使是经验丰富的C 开发人员,在本书中也会发现一些有用的信息和数据。
作者简介
斯蒂芬·罗斯(Stephan Roth)是德国汉堡一家咨询公司的系统和软件工程导师、顾问和培训师。在此之前,他在无线电侦察和通信情报系统领域做了多年的软件开发工程师、软件架构师和系统工程师。Stephan还是一位的演说家及作家,目前已出版多本专业书籍。此外,他还是一个坚定的软件工艺运动支持者,关注于简洁代码开发的规范制定及实践。
目录信息
关于作者
关于技术审校
致谢
第1章 简介1
1.1 软件熵2
1.2 整洁的代码4
1.3 为什么使用C 4
1.4 C 11—新时代的开始5
1.5 适合本书的读者5
1.6 本书使用的约定6
1.6.1 扩展阅读6
1.6.2 说明、提示和警告6
1.6.3 示例代码7
1.6.4 编码风格7
1.7 相关网站和代码库7
1.8 UML图8
第2章 构建安全体系9
2.1 测试的必要性9
2.2 测试入门11
2.3 单元测试13
2.4 关于QA15
2.5 良好的单元测试原则16
2.5.1 单元测试的代码的质量16
2.5.2 单元测试的命名16
2.5.3 单元测试的独立性17
2.5.4 一个测试一个断言18
2.5.5 单元测试环境的独立初始化19
2.5.6 不对getters和setters做单元测试19
2.5.7 不对第三方代码做单元测试20
2.5.8 不对外部系统做单元测试20
2.5.9 如何处理数据库的访问20
2.5.10 不要混淆测试代码和产品代码21
2.5.11 测试必须快速执行23
2.5.12 测试替身24
第3章 原则27
3.1 什么是原则27
3.2 保持简单和直接原则(KISS)28
3.3 不需要原则(YAGNI)29
3.4 避免复制原则(DRY)29
3.5 信息隐藏原则30
3.6 高内聚原则33
3.7 松耦合原则35
3.8 小心优化原则38
3.9 最少惊讶原则(PLA)39
3.10 童子军原则39
第4章 C 代码整洁的基本规范41
4.1 良好的命名42
4.1.1 名称应该自解释43
4.1.2 使用域中的名称45
4.1.3 选择适当抽象层次的名称45
4.1.4 避免冗余的名称46
4.1.5 避免晦涩难懂的缩写47
4.1.6 避免匈牙利命名和命名前缀47
4.1.7 避免相同的名称用于不同的目的48
4.2 注释49
4.2.1 让写代码像讲故事一样49
4.2.2 不要为易懂的代码写注释50
4.2.3 不要通过注释禁用代码50
4.2.4 不要写块注释51
4.2.5 特殊情况的注释是有用的53
4.3 函数56
4.3.1 只做一件事情59
4.3.2 让函数尽可能小59
4.3.3 函数命名61
4.3.4 使用容易理解的名称61
4.3.5 函数的参数和返回值62
4.4 C 工程中的C风格代码72
4.4.1 使用C 的string和stream替代C风格的char*73
4.4.2 避免使用printf()、sprintf()和gets()等74
4.4.3 使用标准库的容器而不是C风格的数组77
4.4.4 用C 类型转换代替C风格的强制转换80
4.4.5 避免使用宏81
第5章 现代C 的高级概念83
5.1 资源管理84
5.1.1 资源申请即初始化85
5.1.2 智能指针86
5.1.3 避免显式的new和delete92
5.1.4 管理特有资源92
5.2 Move语义94
5.2.1 什么是Move语义94
5.2.2 左值和右值的关系95
5.2.3 右值引用96
5.2.4 不要滥用Move97
5.2.5 零原则98
5.3 编译器是你的搭档102
5.3.1 自动类型推导102
5.3.2 编译时计算105
5.3.3 模板变量107
5.4 不允许未定义的行为108
5.5 Type-Rich编程110
5.6 了解你使用的库116
5.6.1 熟练使用116
5.6.2 熟练使用Boost121
5.6.3 应该了解的一些库121
5.7 恰当的异常和错误处理机制122
5.7.1 防患于未然123
5.7.2 异常即异常—字面上的意思126
5.7.3 如果不能恢复则尽快退出128
5.7.4 用户自定义异常128
5.7.5 值类型抛出,常量引用类型捕获130
5.7.6 注意catch的正确顺序130
第6章 面向对象131
6.1 面向对象思想132
6.2 抽象—解决复杂问题的关键因素133
6.3 类的设计原则134
6.3.1 让类尽可能小134
6.3.2 单一职责原则(SRP)135
6.3.3 开闭原则(OCP)135
6.3.4 里氏替换原则(LSP)136
6.3.5 接口隔离原则(ISP)146
6.3.6 无环依赖原则148
6.3.7 依赖倒置原则(DIP)151
6.3.8 不要和陌生人说话(迪米特法则)156
6.3.9 避免“贫血类”160
6.3.10 只说不问160
6.3.11 避免类的静态成员162
第7章 函数式编程164
7.1 什么是函数式编程165
7.1.1 什么是函数166
7.2.2 pure函数和impure函数167
7.2 现代C 中的函数式编程168
7.2.1 C 模板函数编程168
7.2.2 仿函数170
7.2.3 绑定和函数包装176
7.2.4 Lambda表达式178
7.2.5 通用Lambda表达式(C 14)180
7.3 高阶函数181
7.4 整洁的函数式编程代码186
第8章 测试驱动开发188
8.1 普通的旧单元测试的缺点189
8.2 测试驱动开发作为颠覆者190
8.2.1 TDD的流程190
8.2.2 TDD的一个小例子:Code Kata193
8.3 TDD的优势210
8.4 什么时候不应该使用TDD212
第9章 设计模式和习惯用法213
9.1 设计原则与设计模式214
9.2 常见的设计模式及应用场景214
9.2.1 依赖注入模式215
9.2.2 Adapter模式226
9.2.3 Strategy模式227
9.2.4 Command模式231
9.2.5 Command处理器模式235
9.2.6 Composite模式238
9.2.7 Observer模式241
9.2.8 Factory模式245
9.2.9 Facade模式248
9.2.10 Money Class模式249
9.2.11 特例模式252
9.3 什么是习惯用法255
附录A UML简要指南266
参考文献275
· · · · · · (收起)
读后感
1、Good Names Source code files, namespaces, classes, templates, functions, arguments, variables, and constants should have meaningful and expressive names. Names Should Be Self-Explanatory:以下是一些bad names和good names Use Names from the Domain:DDD(Dom...
1、Good Names Source code files, namespaces, classes, templates, functions, arguments, variables, and constants should have meaningful and expressive names. Names Should Be Self-Explanatory:以下是一些bad names和good names Use Names from the Domain:DDD(Dom...
1、Good Names Source code files, namespaces, classes, templates, functions, arguments, variables, and constants should have meaningful and expressive names. Names Should Be Self-Explanatory:以下是一些bad names和good names Use Names from the Domain:DDD(Dom...
1、Good Names Source code files, namespaces, classes, templates, functions, arguments, variables, and constants should have meaningful and expressive names. Names Should Be Self-Explanatory:以下是一些bad names和good names Use Names from the Domain:DDD(Dom...
1、Good Names Source code files, namespaces, classes, templates, functions, arguments, variables, and constants should have meaningful and expressive names. Names Should Be Self-Explanatory:以下是一些bad names和good names Use Names from the Domain:DDD(Dom...
用户评价
对于那些在大型项目中摸爬滚打多年的工程师而言,这本书的价值在于它提供了一套可落地的、面向“长期生存”的开发策略。书中反复强调的“适应变化”的能力,不再是空泛的口号。作者通过展示如何构建可插拔的插件系统,并利用现代C++的面向概念(Concepts,虽然C++20才正式加入,但书中对类似思想的探讨非常深入)的思路来解耦组件,给了我极大的启发。我以前依赖大量的虚函数和RTTI,导致系统耦合度极高,每次修改都需要小心翼翼。而现在,我正在尝试用更偏向于“值语义”和“编译期多态”的方式来重构,这本书中的范例无疑是最好的蓝图。它不仅教我如何写出高效的代码,更重要的是,如何写出能“活得久”的代码。
坦白说,这本书的阅读门槛不低,它假设读者已经对C++有相当的积累,但正是这种挑战性,才使得最终的收获显得格外珍贵。它没有回避C++那些晦涩难懂的部分,比如右值引用和移动语义的深层机制,反而将其作为构建高效抽象的基石。我尤其喜欢它对RAII模型在资源管理之外的更广泛应用——比如状态管理和生命周期控制——的探讨。书中关于异常安全保证的讲解,不再是简单的“什么是强异常安全”,而是提供了具体的、基于C++标准库特性的实现路径。这使得我在设计关键业务流程时,能更有底气地承诺各种级别的安全保障,而不是凭感觉写代码。这种将理论与实战完美结合的叙述风格,让人感觉不是在读一本技术书,而是在跟一位经验丰富的大师进行一对一的密谈。
这本书最打动我的地方,在于它对“自动化测试”与“代码质量”之间关系的深刻解读。它清晰地指出,只有当我们编写的代码结构足够清晰、依赖关系足够明确时,才有可能实现真正有效、覆盖面广的单元测试。书中介绍的那套基于Mocking框架和Test-Driven Development(TDD)的C++实践,非常贴合实际工业界的痛点。例如,如何优雅地隔离那些难以实例化的底层硬件交互代码,作者提供的方法既避免了过度设计,又确保了测试的可行性。这种实用的、面向工程效率的视角,让我意识到整洁代码并非仅仅是代码审查时被挑剔的点,而是提高整个开发团队交付速度和稳定性的核心驱动力。这本书无疑是为那些渴望从“能用”跨越到“卓越”的C++工程师准备的宝典。
这本横空出世的编程指南,对于我这种常年在C++的泥潭里挣扎的开发者来说,简直就是久旱逢甘霖。我尤其欣赏作者在讲解设计模式时,那种深入骨髓的洞察力。不同于市面上那些堆砌概念的教材,这里的案例都是鲜活的、直击痛点的。比如,在处理复杂并发场景时,书里对原子操作和内存模型的细致剖析,让我茅塞顿开。我过去总觉得C++的内存管理晦涩难懂,但读完这部分后,那种“原来如此”的感觉油然而生。它不是简单地告诉你“该怎么做”,而是解释了“为什么非得这么做”,这种追根溯源的讲解方式,极大地提升了我对现代C++特性的理解深度。而且,作者对C++17新特性的运用,也远超出了简单的语法介绍,而是将其融入到更宏大的软件架构设计中,让那些新特性真正发挥出了它们应有的价值,构建出更具韧性和可维护性的系统。
读完这本书,最大的感受是,它真的让我对“整洁”这个词有了全新的定义。这不再是代码格式化的表面功夫,而是渗透到类结构、函数签名、乃至整个模块组织中的一种哲学。书中对于如何利用模板元编程来消除运行时开销的阐述,简直是艺术品级别的。我记得有一个关于实现一个高性能、类型安全的配置加载器的章节,作者巧妙地结合了`constexpr`和编译期计算,将原本需要大量运行时检查的逻辑压缩到了编译阶段,这不仅带来了性能上的飞跃,更从根本上提升了代码的健壮性。这种将“正确性”放在首位的编程理念,对我现有代码库的重构起到了巨大的指导作用。我开始学着用更挑剔的眼光审视每一个函数签名,思考它们是否足够清晰、足够表达意图,而不是仅仅能跑起来了事。
温习到了《代码整洁之道》和《EFFECTIVE C++》中的很多东西,也见识了一些没有学习的新内容。大概不能说多崭新和新潮,但确实能提高不少C++熟练度。
感觉都有道理,但又似乎矛盾,大概有些地方是tradeoff
C++17的内容不多;一些观点确实冲击了我的认识
前段充满了幽默感,读起来很畅快,最后一章感觉有点草草了事…作为200多页的书价格有点偏贵。
C++17的内容不多;一些观点确实冲击了我的认识