《C++代码整洁之道:C++17 可持续软件开发模式实践》
华章程序员书库
C++代码整洁之道:C++17 可持续软件开发模式实践
Clean C++: Sustainable Software Development Patterns and Best Practices with C++ 17
[德]斯蒂芬·罗斯(Stephan Roth)著
连少华 郭发阳 陈涛 译
The Translator's Words 译 者 序
首先,欢迎入坑!自己选择的路,就算跪着也要走完。C++是王者的语言,是强者的工具,如果没有披荆斩棘的勇气,建议你尽快学习其他简单的语言。
本书不是C++入门图书,书中极少讲述C++的语法,也没有提及任何C++高深莫测的技巧,但书中涵盖了单元测试、常用的基本原则、整洁代码的基础、现代C++编程的高级概念、面向对象的基本原则、函数式编程、测试驱动开发(TDD)及经典的设计模式等诸多方面的知识。作者在撰写每一章节的时候,都假设读者已经具备了一定的基础知识,所以如果你是C++语言的初学者,建议你先打好C++的基础再来阅读本书,否则恐怕会浪费你宝贵的时间和有限的精力。
如果你有幸在茫茫书海中发现并购买了本书,如果你真的是C++的初学者(注意:C++和C有着本质的区别,它们是两种完全不同的语言,所以即使你是C语言高手,如果你以前没有C++的经验,那么你也只能算是C++的初学者,可能很多人并不认同这个观点,那说明对C++还没有足够的了解),那么,我衷心地建议你首先阅读最新版的《C++ Primer》,我认为那本书比较适合C++入门。
C++的学习之路,与很多语言的学习之路(如Java、C#、Python等)相比是比较艰难的。因为学习C++,不仅仅是学习语言本身,在学习过程中会涉及多方面的知识。如果你能熟练掌握计算机的基础理论,那么学起来会相对容易一些;如果你能读懂汇编代码,那么在探究C++编译器底层实现的时候也会有很大的帮助;如果你没有良好的设计思想,那么很容易写成C风格的C++代码,所以在掌握C++的基本语法后,还需要逐步训练自己的面向对象思维。面向对象是基础,设计模式是提高,缺一不可。只有这些就够了吗?当然不是,还需要学习更多的东西才能学以致用!比如:STL库、并发编程、网络I/O模型、调试工具、第三方库等。但是不建议学习与界面有关的任何库,因为这恰恰是C++的短板。由此可见,学习C++会涉及方方面面的内容,学习过程的艰难与困惑可想而知。但学习C++有一个极大的好处—一旦能够驾驭C++了,那么你再去学习其他的语言,就会轻车熟路,你将会发现其他语言与C++相比,只是语法不同而已,同时也有助于你更深入地了解其他语言的底层实现,最终达到语言无界、触类旁通的高度。
阅读本书前,建议你具备以下基础:
1. 了解单元测试的概念,最好有使用某单元测试框架编写单元测试的经验,这样你会有更深刻的体会;
2. 了解C++11、C++14、C++17的新特性,如智能指针、Move语义等;
3. 具有面向对象开发的基础,最好知道一些基本的原则,如单一职责、开闭原则等;
4. 了解测试驱动开发的基本思想;
5. 至少听说过设计模式;
6. 能看懂UML类图;
7. 最重要的一点:不满足现状,迫切想改变现在的自己。
拿到本书的英文原版,初步浏览内容后我就被这本书吸引了。我找了几个同样有兴趣的人一起来翻译这本书。我们利用工作之余进行翻译,经常翻译到凌晨,周末也会推掉各种安排及活动,但我们依然遇到了许多困难,针对一些有争议的术语、内容等我们查阅了大量的资料。翻译完成后,我们又进行了仔细的推敲和校对,即使如此,仍然难免存在疏忽、遗漏的地方。受限于译者的水平,也可能存在一些翻译错误或不准确的地方,如果你在阅读过程中刚好发现了问题,你可以向出版社反馈。我们的初衷是帮助想学好C++的同仁,希望本书能够促进你的学习,而不是对你造成误导。
在此,我非常感谢和我一起翻译的几位同仁,他们是郭发阳、陈涛、骆名樊,是你们的加班加点让翻译进行得如此顺利;是你们的努力付出让进度一直处在可控范围。
由于篇幅原因,我无法在这里给出你在每个阶段应该阅读的主要书籍。我现在是CSDN C/C++大版的版主和C++小版的版主,你可以在CSDN网站与我私下交流。
感谢出版社给予了我们无比的信任和翻译的机会,感谢你们选择了这本书!希望本书的内容及译文没有让你们失望。
连少华
2018年12月
About the Author 关 于 作 者
Stephan Roth,出生于1968年5月15日,是一位永远充满激情的导师、顾问。他在德国汉堡一个著名的咨询公司oose Innovative Informatik eG担任系统和软件工程师培训师。在加入该咨询公司之前,Stephan在无线电侦查及通信领域工作多年,担任过软件开发工程师、软件架构师和系统工程师等。期间他开发过大量复杂的应用,尤其是高性能的分布式系统,以及基于C++及其他编程语言完成的图形用户界面。Stephan还是一位优秀的演说家及作家,目前已出版多本专业书籍。作为Gesellschaft für Systems Engineering e.V.(国际系统工程组织INCOSE德国分会)的一员,他还加入了系统工程社区。此外,他还是一个坚定的软件工艺运动支持者,关注于简洁代码开发的规范制定及实践。
Stephan和妻子Caroline、儿子Maximilian现居住于Bad Schwartau,德国波罗的海附近的温泉疗养地。
你可以通过roth-soft.de访问Stephon的个人网站和博客,那里有许多关于系统开发、软件开发和软件工艺的技巧,需要注意的是这些文章主要是用德语写的。
除此之外,你还可以通过电子邮件或其他方式联系他:
E-Mail: stephan@clean-cpp.com
Twitter: @_StephanRoth (https://twitter.com/_StephanRoth)
Google+ Profile Page: http://gplus.to/sro
LinkedIn: http://www.linkedin.com/pub/stephan-roth/79/3a1/514
关于技术审校 About the Technical Reviewer
本书的技术审校Marc Gregoire是一位来自比利时的软件工程师,他毕业于比利时鲁汶大学, 获得了“Burgerlijk ingenieur in de computer wetenschappen”学位。在获得该学位一年后,他在同一所大学以优等成绩获得了人工智能方面的硕士学位。学业完成以后,Marc开始在一家叫作Ordina Belgium的软件咨询公司工作,后来为西门子和诺基亚西门子网络公司工作,主要为电信运营商在Solaris上运行关键的2G 和3G 软件,这需要在一个包括多个洲的国际团队中工作。现在Marc在Nikon Metrology公司工作,从事3D激光扫描软件相关的工作。
他的主要特长是C/C++,特别是微软VC++和MFC框架,他拥有在Windows和Linux平台上开发运行24小时全天候C++程序的经验,例如KNX/EIB家庭自动化软件。除了C/C++,Marc还喜欢C#语言,并用PHP构建网页。
自2007年4月以来,他因自己的Visual C++专业知识获得了年度微软MVP(Most Valuable Professional)奖项。
Marc是比利时C++用户组的创始人(www.becpp.org),也是《Professional C++》的作者,还是CodeGuru论坛(如Marc G)的成员。他的博客网址为:www.nuonsoft.com/blog/ 。
Acknowdedgements 致 谢
能写出本书并不仅是作者一个人的功劳,很多优秀的人也为本书的编写做出了重大的贡献。
首先,我要感谢Apress的Steve Anglin,Steve在2016年3月联系上我,并且说服我和Apress Media LLC一起继续我的新书编写项目,那时该项目已经在Leanpub自出版,真是太幸运了,非常感谢你,亲爱的Steve。之后,我们在2016年7月签订了合同。另外,我还要感谢精湛的自出版平台Leanpub,是它多年来充当了本书的“孵化器”。
其次,我要感谢Apress的编辑业务经理Mark Powers在我撰写手稿期间对我的大力支持。Mark总能在我需要时回答我的问题,他对手稿的不停跟进,对我来说是一种积极的促进,非常感谢你,亲爱的Mark。此外,我还要非常感谢Apress的首席产品开发编辑Matthew Moodie在整本书的编写过程中对我提供的恰当帮助。
特别感谢我的技术审校Marc Gregoire。Marc,非常感谢你带着批判的眼光检查了每一章内容,你发现了很多我可能从未发现的问题,你督促着我改进了几个部分,那些地方对我来说是非常有价值的。
当然,我还要对Apress的整个产品生产团队说一声非常感谢,他们已经出色完成了整本书的最后工作(编辑、索引、作图、排版等),直到最终版的纸质书(和电子书)发布。
当然,我也很感谢我在oose公司的所有同事,感谢你们鼓舞人心的讨论。
最后,但同样重要的是,我要感谢我心爱的也是独一无二的家人,特别是他们对我的理解,毕竟写一本书要花很多时间。Maximilian和Caroline,你们真是太好了!
目 录 Contents
译者序
关于作者
关于技术审校
致谢
2.5.6 不对getters和setters做单元测试19
第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 熟练使用<algorithm>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
- 点赞
- 收藏
- 关注作者
评论(0)