新普京网站-澳门新普京 > 前端 > 高质量程序设计指南C,编程风格指南

高质量程序设计指南C,编程风格指南

2019/12/29 23:56

5.6. 友元

大家允许合理的使用友元类及友元函数.

平日友元应该定义在同等文件内, 防止代码读者跑到其余文件查找使用该民用成员的类. 常常用到友元的一个地点是将 FooBuilder 声明为 Foo 的友元, 以便 FooBuilder 准确布局 Foo 的内部原因, 而无需将该情形暴流露来. 有些意况下, 将贰个单元测量试验类注解成待测类的友元会很方便.

友元扩张了 (但还未有打破卡塔尔 类的包裹边界. 有个别景况下, 相对于将类成员声称为 public, 使用友元是更好的采纳, 尤其是假诺你只允许另二个类访问该类的个人成员时. 当然, 大非常多类都只应该通过其提供的国有成员进行互操作.

内容简要介绍:

5.24. C++11

拾贰分用 C++11(前身是 C++0x)的库和语言扩张,在贵项目用 C++11 性情前三思可移植性。

定义:

C++11 有成都百货上千言语和库上的`变革 < 。

优点:

在二〇黄金年代四年111月事情未发生前,C++11 黄金时代度是官方正规,被多数 C++ 编写翻译器扶持。它规范化非常多大家原先就在用的 C++ 增加,简化了累累操作,大大更正了品质和三沙。

缺点:

C++11 相对于前身,复杂极了:1300 页 vs 800 页!超多开荒者也有些熟谙它。于是从悠久来看,前面八个个性对代码可读性以至维护代价难以预估。大家说不好几时接受其性状,极其是在被迫信任诚笃工具的花色上。

和 5.23. Boost 库 相仿,某个 C++11 扩张提倡实则对可读性有剧毒的编制程序执行——好似去除冗余检查(举例类型名)以助手读者,或是鼓劲模板元编制程序等等。有个别扩大在效果与利益上与原来编写制定冲突,轻巧形成郁结以致搬迁代价。

缺点:

C++11 天性除了个别情形下,能够用生机勃勃用。除了本指南会有超级多章节会加以讨若干 C++11 特性之外,以下特征最好不要用:

  • 尾置重返类型,举个例子用 auto foo() -> int 代替 int foo(). 为了合作于现存代码的扬言风格。
  • 编写翻译时合数 <ratio>, 因为它事关一个重模板的接口风格。
  • <cfenv> 和 <fenv.h> 头文件,因为编写翻译器尚不协理。
  • 默认 lambda 捕获。

图片 1

5.23. Boost 库

只利用 Boost 中被确定的库.

定义:

Boost 库集 是三个广受招待, 经过同行业评比议, 免费开源的 C++ 库集.

优点:

Boost代码品质大范围较高, 可移植性好, 增补了 C++ 规范库相当多空荡荡, 如型其余本性, 更康健的绑定器, 越来越好的智能指针。

缺点:

某个 Boost 库提倡的编制程序试行可读性差, 举个例子元编制程序和其他高等模板技艺, 以至过度 “函数化” 的 class="wp_keywordlink">编制程序风格.

结论:

为了向阅读和掩护代码的人士提供越来越好的可读性, 大家只允许行使 Boost 生机勃勃部分经确认的天性子集. 如今同意选用以下库:

  • Call Traits : boost/call_traits.hpp
  • Compressed Pair : boost/compressed_pair.hpp
  • <The Boost Graph Library (BGL) : boost/graph, except serialization (adj_list_serialize.hpp) and parallel/distributed algorithms and data structures(boost/graph/parallel/* and boost/graph/distributed/*)
  • Property Map : boost/property_map.hpp
  • The part of Iterator that deals with defining iterators: boost/iterator/iterator_adaptor.hppboost/iterator/iterator_facade.hpp, and boost/function_output_iterator.hpp
  • The part of Polygon that deals with Voronoi diagram construction and doesn’t depend on the rest of Polygon: boost/polygon/voronoi_builder.hppboost/polygon/voronoi_diagram.hpp, and boost/polygon/voronoi_geometry_type.hpp
  • Bimap : boost/bimap
  • Statistical Distributions and Functions : boost/math/distributions
  • Multi-index : boost/multi_index
  • Heap : boost/heap
  • The flat containers from Container: boost/container/flat_map, and boost/container/flat_set

笔者们正在主动思考扩大其余 Boost 性子, 所以列表中的法则将不断变化.

以下库能够用,但出于现在已经被 C++ 11 标准库替代,不再鼓舞:

  • Pointer Container : boost/ptr_container, 改用 std::unique_ptr
  • Array : boost/array.hpp, 改用 std::array

高素质程序设计指南C++/C语言(第3版)PDF版 下载地址

5.8. 运营时类型识别

TODO

大家严令禁用 RTTI.

定义:

RTTI 允许 class="wp_keywordlink">程序员在运作时识别 C++ 类对象的类型. 它经过采纳 typeid 或者 dynamic_cast 完成.

优点:

RTTI 的正经代替 (下边将陈诉卡塔尔(قطر‎ 必要对有标题标类层级进行改良或重构. 不常那样的退换并非大家所想要的, 以至是不可取的, 尤其是在一个曾经普及应用的仍旧成熟的代码中.

RTTI 在少数单元测量试验中非常有用. 比方实行工厂类测量试验时, 用来证实二个新建对象是或不是为梦想的动态类型. RTTI 对于管理对象和派生对象的涉嫌也很有用.

在思谋多个抽象对象时 RTTI 也很好用. 举例:

bool Base::Equal(Base* other) = 0;
bool Derived::Equal(Base* other) {
  Derived* that = dynamic_cast<Derived*>(other);
  if (that == NULL)
    return false;
  ...
}

缺点:

在运作时剖断项目日常意味着安排难点. 假如你须求在运行时期明确三个目的的种类, 那日常表明你须求酌量重新设计你的类.

率性地选择 RTTI 会令你的代码难以维护. 它使得基于项目标判别树可能switch 语句传布在代码随处. 如若现在要开展修正, 你就非得检查它们.

结论:

RTTI 有客观的用项然而轻便被滥用, 因而在动用时请必需注意. 在单元测量试验中得以选拔 RTTI, 可是在其余代码中请尽量制止. 越发是在新代码中, 使用 RTTI 前必须三思. 即便您的代码需求依赖区别的目的类型试行不后生可畏的一坐一起来讲, 请思谋用以下的二种替代方案之意气风发查询类型:

虚函数能够依赖子类类型的两样而推行区别代码. 那是把职业付出了目的自己去处理.

假定那大器晚成做事要求在对象之外实现, 能够虚构采纳重复分发的方案, 比如利用访谈者设计方式. 这就能够在对象之外举办项目决断.

意气风发经程序能够确定保证给定的基类实例实际上都以某个派生类的实例, 那么就可以无约束使用 dynamic_cast. 在此种情景下, 使用 dynamic_cast 也是风姿浪漫种代替方案.

凭借项目标论断树是三个很强的暗示, 它表达你的代码已经偏离正轨了. 不要像上边那样:

if (typeid(*data) == typeid(D1)) {
  ...
} else if (typeid(*data) == typeid(D2)) {
  ...
} else if (typeid(*data) == typeid(D3)) {
...

大器晚成经在类层级中投入新的子类, 像那样的代码往往会崩溃. 並且, 后生可畏旦某些子类的本性改换了, 你很难找到并校勘全数受影响的代码块.

不要去手工业达成三个好像 RTTI 的方案. 反驳 RTTI 的理由相同适用于那些方案, 比方带项指标签的类继承体系. 并且, 这么些方案会蒙蔽你的真实意图.

                                <p>第1章 高素质软件开拓之道
1.1 软件品质基本概念
1.1.1 怎么着了解软件的品质
1.1.2 升高软件品质的主导措施
1.1.3 “零缺陷”理念
1.2 细说软件质量属性
1.2.1 正确性
1.2.2 健壮性
1.2.3 可靠性
1.2.4 性能
1.2.5 易用性
1.2.6 清晰性
1.2.7 安全性
1.2.8 可扩张性
1.2.9 兼容性
1.2.10 可移植性
1.3 大家关怀的不仅是质量
1.3.1 品质、分娩率和资本之间的关联
1.3.2 软件进程改进的基本概念
1.4 高素质软件开荒的着力办法
1.4.1 营造软件进程标准
1.4.2 复用
1.4.3 分而治之
1.4.4 优化与折中
1.4.5 技能评定核实
1.4.6 测试
1.4.7 品质承保
1.4.8 改错
1.5 关于软件开辟的有个别常识和思谋
1.5.1 有最佳的编制程序语言吗
1.5.2 编制程序是一门艺术啊
1.5.3 编制程序时应该多接纳技术吧
1.5.4 换更加快的Computer仍旧换越来越快的算法
1.5.5 错误是还是不是相应分品级
1.5.6 一些破绽百出的思想
1.6 小结
第2章 编制程序语言发展简史
2.1 编制程序语言大事记
2.2 Ada的故事
2.3 C/C++发展简史
2.4 Borland与Microsoft之争
2.5 Java阵营与Microsoft的较量
2.6 小结
第3章 程序的基本概念
3.1 程序设计语言
3.2 语言达成
3.3 程序库
3.4 开拓条件
3.5 程序的办事原理
3.6 非凡的编制程序习贯
第4章 C++/C程序设计入门
4.1 C++/C程序的基本概念
4.1.1 运维函数main(卡塔尔
4.1.2 命令行参数
4.1.3 内部名称
4.1.4 连接规范
4.1.5 变量及其开始化
4.1.6 C Runtime Library
4.1.7 编写翻译时和平运动作时的例外
4.1.8 编写翻译单元和独立编写翻译本事
4.2 基本数据类型和内部存款和储蓄器影象
4.3 类型转变
4.3.1 隐式转换
4.3.2 强制调换
4.4 标识符
4.5 转义系列
4.6 运算符
4.7 表达式
4.8 基本调控构造
4.9 选择(判断)结构
4.9.1 布尔变量与零值相比
4.9.2 整型变量与零值比较
4.9.3 浮点变量与零值比较
4.9.4 指针变量与零值比较
4.9.5 对if语句的补充表达
4.9.6 switch结构
4.10 循环(重复)结构
4.10.1 for语句的轮回调控变量
4.10.2 循环语句的功用
4.11 结构化程序设计原理
4.12 goto/continue/break语句
4.13 示例
第5章 C++/C常量
5.1 认识常量
5.1.1 字面常量
5.1.2 符号常量
5.1.3 左券性常量
5.1.4 枚举常量
5.2 准明确义符号常量
5.3 const与#define的比较
5.4 类中的常量
5.5 实际行使中哪些定义常量
第6章 C++/C函数设计基本功
6.1 认知函数
6.2 函数原型和概念
6.3 函数调用方式
6.4 认知函数客栈
6.5 函数调用标准
6.6 函数连接标准
6.7 参数字传送递法规
6.8 重返值的平整
6.9 函数内部落实的平整
6.10 存款和储蓄类型及成效域准绳
6.10.1 存款和储蓄类型
6.10.2 成效域法规
6.10.3 连接类型
6.11 递归函数
6.12 使用断言
6.13 使用const进步等函大数的强壮性
6.13.1 用const修饰函数的参数
6.13.2 用const修饰函数的再次来到值
第7章 C++/C指针、数组和字符串
7.1 指针
7.1.1 指针的精气神
7.1.2 指针的门类及其帮忙的运算
7.1.3 指针传递
7.2 数组
7.2.1 数组的庐山真面目目
7.2.2 二维数组
7.2.3 数组传递
7.2.4 动态创制、伊始化和删除数组的章程
7.3 字符数组、字符指针和字符串
7.3.1 字符数组、字符串和''的关系
7.3.2 字符指针的误区
7.3.3 字符串拷贝和相比较
7.4 函数指针
7.5 援用和指针的相比
第8章 C++/C高端数据类型
8.1 结构(struct)
8.1.1 关键字struct与class的困惑
8.1.2 使用struct
8.1.3 位域
8.1.4 成员对齐
8.2 联合(Union)
8.3 枚举(Enum)
8.4 文件
第9章 C++/C编写翻译预管理
9.1 文件包蕴
9.1.1 内部含有卫哨和表面包涵卫哨
9.1.2 头文件满含的客体顺序
9.2 宏定义
9.3 条件编译
9.3.1 #if、#elif和#else
9.3.2 #ifdef 和 #ifndef
9.4 #error
9.5 #pragma
9.6 #和##运算符
9.7 预约义符号常量
第10章 C++/C文件结构和程序版式
10.1 程序文件的目录布局
10.2 文件的布局
10.2.1 头文件的用项和布局
10.2.2 版权和版本消息
10.2.3 源文件布局
10.3 代码的版式
10.3.1 适当的空行
10.3.2 代码行及行内空格
10.3.3 长行拆分
10.3.4 对齐与缩进
10.3.5 修饰符的任务
10.3.6 注释风格
10.3.7 ADT/UDT版式
第11章 C++/C应用程序命名法则
11.1 共性法则
11.2 轻便的Windows应用程序命名
第12章 C++面向对象程序设计方法概述
12.1 漫谈面向对象
12.2 对象的概念
12.3 音讯隐讳与类的包裹
12.4 类的持续性子
12.5 类的重新组合性情
12.6 动态性格
12.6.1 虚函数
12.6.2 抽象基类
12.6.3 动态绑定
12.6.4 运转时多态
12.6.5 多态数组
12.7 C++对象模型
12.7.1 对象的内部存款和储蓄器影像
12.7.2 隐含成员
12.7.3 C++编写翻译器如哪处理成员函数
12.7.4 C++编写翻译器如哪儿理静态成员
12.8 小结
第13章 对象的开头化、拷贝和析构
13.1 结构函数与析构函数的来自
13.2 为啥必要布局函数和析构函数
13.3 构造函数的积极分子初阶化列表
13.4 指标的协会和析构次序
13.5 布局函数和析构函数的调用机遇
13.6 布局函数和赋值函数的重载
13.7 示例:类String的结构函数和析构函数
13.8 曾几何时应该定义拷贝构造函数和拷贝赋值函数
13.9 示范:类String的正片布局函数和拷贝赋值函数
13.10 用偷懒的主意管理拷贝布局函数和 拷贝赋值函数
13.11 如何兑现派生类的主干函数
第14章 C++函数的尖端性情
14.1 函数重载的概念
14.1.1 重载的发源
14.1.2 重载是如何完成的
14.1.3 小心隐式类型转变招致重载函数产生二义性
14.2 成员函数的重载、覆盖与潜伏
14.2.1 重载与覆盖
14.2.2 令人迷惑的藏身准则
14.2.3 脱身隐蔽
14.3 参数的暗中认可值
14.4 运算符重载
14.4.1 基本概念
14.4.2 运算符重载的特殊性
14.4.3 无法重载的运算符
14.4.4 重载++和--
14.5 函数内联
14.5.1 用函数内联代替宏
14.5.2 内联函数的编制程序风格
14.5.3 慎用内联
14.6 类型转变函数
14.7 const成员函数
第15章 C++万分管理和RTTI
15.1 为啥要使用非常管理
15.2 C++至极管理
15.2.1 十分管理的原理
15.2.2 卓殊类型和那多少个对象
15.2.3 相当管理的语法构造
15.2.4 分外的项目相称法则
15.2.5 十分表达及其冲突
15.2.6 当格外抛出时部分对象如何释放
15.2.7 对象组织和析构时期的不行
15.2.8 如何行使好丰盛管理技能
15.2.9 C++的正规拾壹分
15.3 虚函数面对的难点
15.4 RTTI及其构成
15.4.1 起源
15.4.2 typeid运算符
15.4.3 dynamic_cast<>运算符
15.4.4 RTTI的魅力与代价
第16章 内部存款和储蓄器管理
16.1 内部存储器分配方式
16.2 多如牛毛的内部存款和储蓄器错误连同对策
16.3 指针参数是如何传递内部存款和储蓄器的
16.4 free和delete把指针怎么啦
16.5 动态内部存款和储蓄器会被机关释放吧
16.6 杜绝“野指针”
16.7 有了malloc/free为何还要new/delete
16.8 malloc/free的选用要点
16.9 new有3种接纳方法
16.9.1 plain new/delete
16.9.2 nothrow new/delete
16.9.3 placement new/delete
16.10 new/delete的选拔要点
16.11 内部存款和储蓄器耗尽如何做
16.12 用对象模拟指针
16.13 泛型指针auto_ptr
16.14 带有引用计数的智能指针
16.15 智能指针作为容器成分
第17章 学习和使用STL
17.1 STL简介
17.2 STL头文件的布满
17.2.1 容器类
17.2.2 泛型算法
17.2.3 迭代器
17.2.4 数学生运动算库
17.2.5 通用工具
17.2.6 别的头文件
17.3 容器设计原理
17.3.1 内部存款和储蓄器影像
17.3.2 存款和储蓄格局和访谈形式
17.3.3 顺序容器和关联式容器的相比
17.3.4 怎么样遍历容器
17.3.5 存款和储蓄空间重分配难点
17.3.6 什么样的目标才干作为STL容器的要素
17.4 迭代器
17.4.1 迭代器的原形
17.4.2 迭代器失效及其危殆性
17.4.3 怎样在遍历容器的进程中准确删除成分
17.5 存款和储蓄分配器
17.6 适配器
17.7 泛型算法
17.8 一些奇特的器皿
17.8.1 string类
17.8.2 bitset并非set
17.8.3 节省存储空间的vector
17.8.4 空容器
17.9 STL容器特征总计
17.10 STL使用体验
附录A C++/C试题
附录B C++/C试题答案与评分规范
附录C 大学十年
附录D 《大学十年》后记
附录E 术语与缩写解释

5.10. 流

只在记录日志时行使流.

定义:

流用来替代 printf() 和 scanf().

优点:

有了流, 在打字与印刷时没有必要关心对象的类型. 不用顾忌格式化字符串与参数列表不相配 (尽管在 gcc 中动用 printf 也不设有那个难题卡塔尔. 流的协会和析构函数会自动张开和停业对应的文件.

缺点:

流使得 pread() 等职能函数很难实践. 假如不行使 printf 风格的格式化字符串, 有些格式化操作 (特别是常用的格式字符串 %.*sState of Qatar 用流管理品质是非常的低的. 流不帮衬字符串操作符重新排序 (%1sState of Qatar, 而这点对于软件国际化很有用.

结论:

绝不使用流, 除非是日记接口需求. 使用 printf 之类的代替.

动用流还可能有非常多优劣势, 但代码后生可畏致性超越一切. 不要在代码中使用流.

张开钻探:

对这一条法规存在一些对立, 这儿给出点深等级次序原因. 回看一下唯朝气蓬勃性原则 (Only One Way卡塔尔(قطر‎: 大家盼望在别的时候都只利用意气风发种鲜明的 I/O 类型, 使代码在具有I/O 处都维持蓬蓬勃勃致. 于是, 大家不指望客户来决定是运用流依旧 printf + read/write. 相反, 大家应有调控到底用哪生机勃勃种情势. 把日记作为特例是因为日志是一个拾贰分出格的施用, 还也许有局地是历史原因.

流的拥护者们看好流是不二之选, 但观点并非那么显然有力. 他们建议的流的种种优势也都以其缺点. 流最大的优势是在出口时无需关心打字与印刷对象的类型. 这是一个亮点. 同有时间, 也是叁个相差: 你超级轻易用错类型, 而编写翻译器不会报告急察方. 使用流时轻易招致的这类错误:

cout << this;   // 输出地址
cout << *this;  // 输出值

由于 << 被重载, 编写翻译器不会报错. 就因为这点我们反驳动用操作符重载.

有人说 printf 的格式化丑陋不堪, 易读性差, 但流也好不到何地去. 看看下边两段代码吧, 完成平等的效果与利益, 哪个更清楚?

cerr << "Error connecting to '" << foo->bar()->hostname.first
     << ":" << foo->bar()->hostname.second << ": " << strerror(errno);

fprintf(stderr, "Error connecting to '%s:%u: %s",
        foo->bar()->hostname.first, foo->bar()->hostname.second,
        strerror(errno));

您可能会说, “把流封装一下就能够比较好了”, 那儿能够, 别的地点啊? 并且不要忘记了, 大家的靶子是使语言更紧凑, 并不是丰盛一些外人需求学习的新器材.

每生机勃勃种艺术都以有利有弊, “未有最棒, 只有更相符”. 轻松性原则告诫我们必需从当中接纳那么些, 最后大繁多调节选择 printf + read/write.

目录

5.15. 64 位下的可移植性

代码应该对 64 位和 32 位系统谐和. 管理打字与印刷, 比较, 布局体对齐时应切记:

对此有些品种, printf() 的提示符在 32 位和 64 位系统上可移植性不是很好. C99 标准定义了后生可畏部分可移植的格式化提醒符. 不幸的是, MSVC 7.1 并不是全数协助, 并且标准中也负有疏漏, 所以有的时候我们只可以自身定义二个丑陋的版本 (头文件 inttypes.h 仿标准风格State of Qatar:

// printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
#define __PRIS_PREFIX "z"
#else
#define __PRIS_PREFIX
#endif

// Use these macros after a % in a printf format string
// to get correct 32/64 bit behavior, like this:
// size_t size = records.size();
// printf("%"PRIuS"n", size);
#define PRIdS __PRIS_PREFIX "d"
#define PRIxS __PRIS_PREFIX "x"
#define PRIuS __PRIS_PREFIX "u"
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
类型 不要使用 使用 备注
void * (或其他指针类型) %lx %p
int64_t %qd, %lld %"PRId64"
uint64_t %qu, %llu, %llx %"PRIu64", %"PRIx64"
size_t %u %"PRIuS", %"PRIxS" C99 规定 %zu
ptrdiff_t %d %"PRIdS" C99 规定 %zd

注意 PRI* 宏会被编写翻译器增添为独立字符串. 因而只要利用极度量的格式化字符串, 须要将宏的值而不是宏名插入格式中. 使用 PRI* 宏相通能够在 % 后蕴含长度提醒符. 举例, printf("x = %30"PRIuS"n", x) 在 32 位 Linux 中校被开展为 printf("x = %30" "u" "n", x), 编写翻译器当成 printf("x = %30un", x) 管理 (Yang.Y 注: 这在 MSVC 6.0 上行不通, VC 6 编译器不会自行把引号间距的七个字符串连接二个长字符串卡塔尔国.

记住 sizeof(void *) != sizeof(int). 要是急需叁个指南针大小的卡尺头要用 intptr_t.

您要特别小心的对待布局体对齐, 极其是要长久化到磁盘上的构造体 (Yang.Y 注: 长久化 – 将数据按字节流顺序保存在磁盘文件或数据库中卡塔尔. 在 64 位系统中, 任何带有 int64_t/uint64_t 成员的类/布局体, 缺省都是 8 字节在结尾对齐. 假诺 32 位和 64 位代码要共用长久化的构造体, 必要保险二种连串构造下的构造体对齐风华正茂致. 大超级多编写翻译器都同意调度布局体对齐. gcc 中可使用 __attribute__((packed)). MSVC 则提供了 #pragma pack() 和 __declspec(align()) (尤尔Fox 注, 建设方案的档案的次序性质里也足以一直设置卡塔尔(قطر‎.

始建 64 位常量时使用 LL 或 ULL 作为后缀, 如:

int64_t my_value = 0×123456789LL;
uint64_t my_mask = 3ULL << 48;

假诺您确实须要 32 位和 64 位系统具有差别代码, 能够选择 #ifdef _LP64 指令来切分 32/64 位代码. (尽量不要那样做, 假如非用不可, 尽量使匡正局地化卡塔尔国

第1章 高水平软件开采之道
1.1 软件品质基本概念
1.1.1 如何驾驭软件的品质
1.1.2 提升软件质量的宗旨办法
1.1.3 “零缺陷”理念
1.2 细说软件品质属性
1.2.1 正确性
1.2.2 健壮性
1.2.3 可靠性
1.2.4 性能
1.2.5 易用性
1.2.6 清晰性
1.2.7 安全性
1.2.8 可扩大性
1.2.9 兼容性
1.2.10 可移植性
1.3 大家关怀的不仅仅是材料
1.3.1 质量、生产率和本金之间的涉嫌
1.3.2 软件进度改正的基本概念
1.4 高水平软件开垦的主导方法
1.4.1 组建软件进度标准
1.4.2 复用
1.4.3 分而治之
1.4.4 优化与折中
1.4.5 本事评定检查核对
1.4.6 测试
1.4.7 质量承保
1.4.8 改错
1.5 关于软件开拓的片段常识和揣摩
1.5.1 有最佳的编制程序语言吗
1.5.2 编制程序是一门艺术呢
1.5.3 编制程序时应该多采用本事吧
1.5.4 换越来越快的微Computer依然换越来越快的算法
1.5.5 错误是还是不是合宜分等第
1.5.6 一些荒诞的守旧
1.6 小结
第2章 编制程序语言发展简史
2.1 编程语言大事记
2.2 Ada的故事
2.3 C/C++发展简史
2.4 Borland与Microsoft之争
2.5 Java阵营与Microsoft的较量
2.6 小结
第3章 程序的基本概念
3.1 程序设计语言
3.2 语言实现
3.3 程序库
3.4 开辟条件
3.5 程序的做事原理
3.6 优越的编制程序习于旧贯
第4章 C++/C程序设计入门
4.1 C++/C程序的基本概念
4.1.1 运营函数main(卡塔尔国
4.1.2 命令行参数
4.1.3 内部名称
4.1.4 连接标准
4.1.5 变量及其发轫化
4.1.6 C Runtime Library
4.1.7 编写翻译时和周转时的不如
4.1.8 编写翻译单元和单身编写翻译技艺
4.2 基本数据类型和内部存款和储蓄器影像
4.3 类型转换
4.3.1 隐式转变
4.3.2 逼迫转变
4.4 标识符
4.5 转义体系
4.6 运算符
4.7 表达式
4.8 基本调节构造
4.9 选择(判断)结构
4.9.1 布尔变量与零值相比
4.9.2 整型变量与零值相比
4.9.3 浮点变量与零值相比较
4.9.4 指针变量与零值比较
4.9.5 对if语句的增加补充表明
4.9.6 switch结构
4.10 循环(重复)结构
4.10.1 for语句的大循环调控变量
4.10.2 循环语句的频率
4.11 构造化程序设计原理
4.12 goto/continue/break语句
4.13 示例
第5章 C++/C常量
5.1 认知常量
5.1.1 字面常量
5.1.2 符号常量
5.1.3 协议性常量
5.1.4 枚举常量
5.2 正确定义符号常量
5.3 const与#define的比较
5.4 类中的常量
5.5 实际运用中什么定义常量
第6章 C++/C函数设计底蕴
6.1 认识函数
6.2 函数原型和概念
6.3 函数调用方式
6.4 认知函数仓库
6.5 函数调用标准
6.6 函数连接标准
6.7 参数传递准则
6.8 再次来到值的法则
6.9 函数内部得以落成的法规
6.10 存款和储蓄类型及功能域法则
6.10.1 存储类型
6.10.2 功能域准绳
6.10.3 连接类型
6.11 递归函数
6.12 使用断言
6.13 使用const升高等函大数的强壮性
6.13.1 用const修饰函数的参数
6.13.2 用const修饰函数的重回值
第7章 C++/C指针、数组和字符串
7.1 指针
7.1.1 指针的原形
7.1.2 指针的连串及其帮助的演算
7.1.3 指针传递
7.2 数组
7.2.1 数组的精气神儿
7.2.2 二维数组
7.2.3 数组传递
7.2.4 动态创设、开端化和删除数组的方式
7.3 字符数组、字符指针和字符串
7.3.1 字符数组、字符串和''的关系
7.3.2 字符指针的误区
7.3.3 字符串拷贝和相比
7.4 函数指针
7.5 引用和指针的可比
第8章 C++/C高端数据类型
8.1 结构(struct)
8.1.1 关键字struct与class的困惑
8.1.2 使用struct
8.1.3 位域
8.1.4 成员对齐
8.2 联合(Union)
8.3 枚举(Enum)
8.4 文件
第9章 C++/C编写翻译预管理
9.1 文件包罗
9.1.1 内部含有卫哨和外界包罗卫哨
9.1.2 头文件包涵的创建顺序
9.2 宏定义
9.3 条件编写翻译
9.3.1 #if、#elif和#else
9.3.2 #ifdef 和 #ifndef
9.4 #error
9.5 #pragma
9.6 #和##运算符
9.7 预订义符号常量
第10章 C++/C文件结商谈次序版式
10.1 程序文件的目录构造
10.2 文件的协会
10.2.1 头文件的用项和构造
10.2.2 版权和版本新闻
10.2.3 源文件结构
10.3 代码的版式
10.3.1 适当的空行
10.3.2 代码行及行内空格
10.3.3 长行拆分
10.3.4 对齐与缩进
10.3.5 修饰符的职责
10.3.6 注释风格
10.3.7 ADT/UDT版式
第11章 C++/C应用程序命名法则
11.1 共性法规
11.2 简单的Windows应用程序命名
第12章 C++面向对象程序设计格局概述
12.1 漫谈面向对象
12.2 对象的定义
12.3 新闻隐蔽与类的卷入
12.4 类的一连天性
12.5 类的组成天性
12.6 动态天性
12.6.1 虚函数
12.6.2 抽象基类
12.6.3 动态绑定
12.6.4 运营时多态
12.6.5 多态数组
12.7 C++对象模型
12.7.1 对象的内存影像
12.7.2 隐含成员
12.7.3 C++编写翻译器如什么地方理成员函数
12.7.4 C++编写翻译器如何处理静态成员
12.8 小结
第13章 对象的起先化、拷贝和析构
13.1 布局函数与析构函数的起点
13.2 为啥需求布局函数和析构函数
13.3 布局函数的分子开头化列表
13.4 目的的结议和析构次序
13.5 布局函数和析构函数的调用时机
13.6 布局函数和赋值函数的重载
13.7 示例:类String的布局函数和析构函数
13.8 曾几何时应该定义拷贝架构函数和拷贝赋值函数
13.9 演示:类String的正片布局函数和拷贝赋值函数
13.10 用偷懒的艺术处理拷贝结构函数和 拷贝赋值函数
13.11 如何促成派生类的着力函数
第14章 C++函数的高等性情
14.1 函数重载的定义
14.1.1 重载的根源
14.1.2 重载是哪些落到实处的
14.1.3 小心隐式类型转换引致重载函数产生二义性
14.2 成员函数的重载、覆盖与潜伏
14.2.1 重载与覆盖
14.2.2 令人吸引的隐身准绳
14.2.3 开脱掩盖
14.3 参数的私下认可值
14.4 运算符重载
14.4.1 基本概念
14.4.2 运算符重载的特殊性
14.4.3 不能够重载的运算符
14.4.4 重载++和--
14.5 函数内联
14.5.1 用函数内联代替宏
14.5.2 内联函数的编制程序风格
14.5.3 慎用内联
14.6 类型调换函数
14.7 const成员函数
第15章 C++万分管理和RTTI
15.1 为啥要动用非常处理
15.2 C++分外管理
15.2.1 非常管理的原理
15.2.2 非常类型和万分对象
15.2.3 非常管理的语法布局
15.2.4 非凡的体系相称法规
15.2.5 至极表明及其冲突
15.2.6 当极度抛出时部分对象怎么样释放
15.2.7 对象组织和析构时期的不胜
15.2.8 怎样使用好丰富管理技能
15.2.9 C++的正统十二分
15.3 虚函数面对的难点
15.4 RTTI及其构成
15.4.1 起源
15.4.2 typeid运算符
15.4.3 dynamic_cast<>运算符
15.4.4 RTTI的吸重力与代价
第16章 内存管理
16.1 内部存款和储蓄器分配方式
16.2 习认为常的内部存款和储蓄器错误连同对策
16.3 指针参数是怎么传递内部存储器的
16.4 free和delete把指针怎么啦
16.5 动态内部存款和储蓄器会被机关释放吧
16.6 杜绝“野指针”
16.7 有了malloc/free为何还要new/delete
16.8 malloc/free的利用要点
16.9 new有3种采用办法
16.9.1 plain new/delete
16.9.2 nothrow new/delete
16.9.3 placement new/delete
16.10 new/delete的采纳要点
16.11 内部存款和储蓄器耗尽咋办
16.12 用对象模拟指针
16.13 泛型指针auto_ptr
16.14 带有援用计数的智能指针
16.15 智能指针作为容器成分
第17章 学习和选用STL
17.1 STL简介
17.2 STL头文件的遍及
17.2.1 容器类
17.2.2 泛型算法
17.2.3 迭代器
17.2.4 数学生运动算库
17.2.5 通用工具
17.2.6 其余头文件
17.3 容器设计原理
17.3.1 内部存款和储蓄器影像
17.3.2 存款和储蓄方式和寻访格局
17.3.3 顺序容器和关联式容器的可比
17.3.4 如何遍历容器
17.3.5 存款和储蓄空间重分配难点
17.3.6 什么样的指标本事当作STL容器的要素
17.4 迭代器
17.4.1 迭代器的面目
17.4.2 迭代器失效及其危殆性
17.4.3 怎么着在遍历容器的进程中国科高校学删除成分
17.5 存款和储蓄分配器
17.6 适配器
17.7 泛型算法
17.8 一些例外的容器
17.8.1 string类
17.8.2 bitset并非set
17.8.3 节省存储空间的vector
17.8.4 空容器
17.9 STL容器特征总计
17.10 STL使用体验
附录A C++/C试题
附录B C++/C试题答案与评分标准
附录C 学院十年
附录D 《高校十年》后记
附录E 术语与缩写解释

5.14. 整型

C++ 内建整型中, 仅使用 int. 假诺程序中须求分歧大小的变量, 可以行使 <stdint.h> 中长度准确的整型, 如 int16_t.若是您的变量只怕十分大于 2^31 (2GiB卡塔尔国, 就用 62人变量比方 int64_t. 此外要留神,哪怕你的值并不会超过 int 所可以代表的界定,在测算进程中也说倒霉会溢出。所以拿不定时,干脆用更加大的连串。

定义:

C++ 未有一点名整型的大小. 平时大家假定 short 是 16 位, int 是 32 位, long 是 32 位, long long是 64 位.

优点:

保持证明统蓬蓬勃勃.

缺点:

C++ 中整型大小因编写翻译器和系统布局的不一样而不相同.

结论:

<stdint.h> 定义了 int16_tuint32_tint64_t 等整型, 在急需保障整型大小时能够使用它们代替 shortunsigned long long 等. 在 C 整型中, 只使用 int. 在适度的图景下, 推荐应用规范项目如 size_t 和 ptrdiff_t.

只要已知整数不会太大, 我们平常会利用 int, 如循环计数. 在看似的状态下行使原生类型 int. 你能够以为 int 起码为 32 位, 但不要感到它会多于 32 位. 假如供给 64 位整型, 用 int64_t 或 uint64_t.

对于大整数, 使用 int64_t.

永不接收 uint32_t 等无符号整型, 除非你是在表示二个位组却非三个数值, 或是你供给定义二进制补码溢出. 特别是决不为了提议数值永不会为负, 而使用无符号类型. 相反, 你应该运用断言来保证数据.

若是你的代码涉及容器重回的轻重(size),确定保证其品种足以应付容器各类只怕的用法。拿不允许时,类型越大越好。

小心整型类型调换和整型升高(acgtyrant 注:integer promotions, 举例 int 与 unsigned int 运算时,前面一个被进级为 unsigned int 而有相当的大希望溢出),总有意料之外的结局。

有关无符号整数:

有一点人, 包涵部分课本小编, 推荐应用无符号类型表示非负数. 这种做法试图到达本身文书档案化. 可是, 在 C 语言中, 那意气风发亮点被由其以致的 bug 所消除. 看看上面包车型地铁事例:

for (unsigned int i = foo.Length()-1; i >= 0; --i) ...

上述循环永世不会脱离! 不经常 gcc 会发掘该 bug 并报告急方, 但大多数场馆下都不会. 相近的 bug 还恐怕会晤世在可比有符合变量和无符号变量时. 首倘使 C 的花色进步机制会变成无符号类型的一言一动出乎你的意料.

因而, 使用断言来提议变量为非负数, 实际不是行使无符号型!

高水平程序设计是软件行当的虚弱环节,超过半数公司为此付出了慷慨振奋的代价,只可以通过大气的测量试验和纠错来加强软件出品的质量。因此,怎样让技术员纯熟地通晓编制程序技巧和编制程序标准,在开垦进程中内建高水平代码,是IT 集团面对的严重性挑战之豆蔻梢头。本书以轻便有趣的调子向读者论述了高素质软件开拓方法与 C++/C 编制程序标准,而那也是小编多年从事软件开垦职业的资历计算。全书共17 章,第1 章到第4 章爱护介绍软件品质和着力的程序设计情势;第5 章到第16 章珍视阐释C++/C 编制程序风格、面向对象程序设计艺术和部分技艺专项论题;第17 章解说STL 的原理和应用方法。本书第 1 版和第2 版部分章节曾在网络海人民广播电视台湾大学流传,被国内IT 集团的数不清软件开垦职员采取。本书的附录C《大学十年》是笔者在英特网公布的叁个短篇传记,文中所陈述的充满激情的上学和生活态度,感染了不可推测莘莘学生。

5.22. 模板编制程序

无须选择复杂的模版编程

定义:

模板编制程序指的是利用c++ 模板实例化学工业机械制是图灵完善性, 能够被用来贯彻编写翻译时刻的花色判定的一文山会海编制程序才干

优点:

模板编制程序能够贯彻特别灵活的类型安全的接口和极好的性质, 一些广泛的工具比如谷歌(GoogleState of Qatar Test, std::tuple, std::function 和 Boost.Spirit. 那个工具若无模板是贯彻持续的

缺点:

  • 模板编制程序所选用的技艺对于使用c++不是很在行的人是相比较猛烈, 难懂的. 在错综相连的地点使用模板的代码令人更不便于读懂, 并且debug 和 维护起来都很劳顿
  • 模板编制程序常常会促成编写翻译出错的新闻特别不自身: 在代码出错的时候, 纵然那个接口极其的精简, 模板内部复杂的贯彻细节也会在失误音讯展现. 引致那么些编写翻译出错音信看起来十一分麻烦精晓.
  • 恢宏的利用模板编制程序接口会让重构工具(Visual Assist X, Refactor for C++等等State of Qatar更难发挥用处. 首先进表率板的代码会在比非常多上下文里面扩张开来, 所以很难确认重构对持有的那么些进展的代码有用, 其次有个别重构工具只对曾经做过模板类型替换的代码的AST 有用. 由此重构工具对那个模板完毕的原始代码并不中用, 很难找寻怎么样须要重构.

结论:

  • 模板编制程序有的时候候可以实现更简明更易用的接口, 可是越来越多的时候却节外生枝. 由此模板编制程序最佳只用在为数相当的少的底子构件, 功底数据布局上, 因为模板带给的附加的护卫花销会被一大波的施用给分担掉
  • 在行使模板编制程序也许别的复杂的模板技巧的时候, 你早晚要频频思量一下. 考虑一下你们共青团和少先队成员的平均水平是不是可以读懂并且能够爱抚您写的模板代码.只怕四个非c++ 技师和部分只是在失误的时候不时看一下代码的人能够读懂那个错误音讯恐怕能够跟踪函数的调用流程. 假若你利用递归的沙盘模拟经营实例化, 或然项目列表, 大概元函数, 又大概说明式模板, 恐怕重视SFINAE, 只怕sizeof 的trick 手段来检查函数是或不是重载, 那么那评释你模板用的太多了, 那一个模板太复杂了, 大家不推荐使用
  • 万风度翩翩你使用模板编程, 你不得不酌量尽大概的把复杂度最小化, 何况尽量不要让模板对外暴漏. 你最佳只在贯彻里面使用模板, 然后给顾客暴光的接口里面并不行使模板, 那样能增长你的接口的可读性. 何况你应有在这里些使用模板的代码上写尽恐怕详尽的注释. 你的疏解里面应该详细的富含这几个代码是怎么用的, 那个模板生成出来的代码差非常少是何等体统的. 还索要非常注目的在于顾客错误使用你的模版代码的时候要求输出更人性化的失误新闻. 因为那一个出错消息也是您的接口的黄金年代局地, 所以你的代码必需调动到那一个错误音信在顾客看起来应当是非常轻巧明白, 并且客商十分轻巧明白怎么改进那个错误

图片 2

5.3. 函数重载

若要用好函数重载,最棒能让读者后生可畏看调用点(call site)就有数,不用花心情估计调用的重载函数到底是哪豆蔻年华种。该准绳适用于布局函数。

定义:

你能够编写贰个参数类型为 const string& 的函数, 然后用另多个参数类型为 const char* 的函数重载它:

class MyClass {
    public:
    void Analyze(const string &text);
    void Analyze(const char *text, size_t textlen);
};

优点:

透过重载参数不一样的同名函数, 令代码更直观. 模板化代码须要重载, 同不时候为使用者带来便利.

缺点:

假设函数单单靠区别的参数类型而重载(acgtyrant 注:那代表参数数量不改变),读者就得不得了熟知 C++ 美妙绝伦的万分准则,以询问相配进程具体到底怎么。其余,当派生类只重载了某个函数的有的变体,世袭语义轻便令人纠葛。

结论:

假设你计划重载二个函数, 能够尝试改在函数名里加上参数音讯。举个例子,用 AppendString() 和 AppendInt() 等, 并不是一口气重载多个 Append().

高水平C/C++编制程序指南

5.19. auto

用 auto 绕过繁杂的品种名,只要可读性好就一而再三回九转用,别用在有个别变量之外的地点。

定义:

C++11 中,若变量被声称成 auto, 那它的门类就能被自动相配成开头化表明式的项目。您能够用 auto 来复制开首化或绑定引用。

vector<string> v;
...
auto s1 = v[0];  // 创建一份 v[0] 的拷贝。
const auto& s2 = v[0];  // s2 是 v[0] 的一个引用。

优点:

C++ 类型名一时又长又臭,特别是关系模板或命名空间的时候。就像:

sparse_hash_map<string, int>::iterator iter = m.find(val);

回到类型好难读,代码指标也缺乏一览理解。重构其:

auto iter = m.find(val);

好多了。

没有 auto 的话,大家只可以在同二个表达式里写同三个档期的顺序名一遍,无谓的双重,就好像:

diagnostics::ErrorStatus* status = new diagnostics::ErrorStatus("xyz");

有了 auto, 可以更便利地用中间变量,显式编写它们的花色轻易点。

缺点:

品类够鲜明时,特别是最初化变量时,代码才会够一览无余。但以下就不雷同了:

auto i = x.Lookup(key);

看不出其系列是什么,x 的品种申明大概远在几百行之外了。

技士必需会区分 auto 和 const auto& 的差异之处,不然会复制错东西。

auto 和 C++11 列表起始化的合体令人胡里胡涂:

auto x(3);  // 圆括号。
auto y{3};  // 大括号。

它们不是同一次事——x 是 inty 则是 std::initializer_list<int>. 此外平时不可以知道的代办项目(acgtyrant 注:normally-invisible proxy types, 它事关到 C++ 不敢问津的坑:Why is vector<bool> not a STL container?)也是有大致的陷阱。

生机勃勃经在接口里用 auto, 举例申明头文件里的一个常量,那么风流倜傥旦仅仅因为技术员不经常修正其值而诱致品种更动的话——API 要倾覆了。

结论:

auto 只好用在一些变量里用。别用在文件作用域变量,命名空间功能域变量和类数据成员里。恒久别列表开端化 auto 变量。

auto 还足以和 C++11 天性「尾置重返类型(trailing return type)」一同用,可是后面一个只好用在 lambda 表明式里。

5.1. 援用参数

负有按引用传递的参数必得抬高 const.

定义:

在 C 语言中, 假如函数必要校订变量的值, 参数必得为指针, 如 int foo(int *pval). 在 C++ 中, 函数还足以注脚援用参数: int foo(int &val).

优点:

概念引用参数幸免现身 (*pval)++ 那样丑陋的代码. 像拷贝布局函数那样的采纳也是少不了的. 何况更生硬, 不接收 NULL 指针.

缺点:

轻易孳生误会, 因为援引在语法上是值变量却有所指针的语义.

结论:

函数参数列表中, 全部援引参数都必需是 const:

void Foo(const string &in, string *out);

骨子里那在 谷歌(Google卡塔尔 Code 是四个硬性约定: 输入参数是值参或 const 援用, 输出参数为指针. 输入参数能够是 const 指针, 但绝对不可能是非 const 的引用参数,除非用于沟通,比如 swap().

不常,在输入形参中用 const T* 指针比 const T& 更明智。比如:

  • 您会传 null 指针。
  • 函数要把指针或对地方的援引赋值给输入形参。

总的说来好些个时候输入形参往往是 const T&. 若用 const T* 表达输入另有管理。所以若您要用 const T*, 则应有理有据,不然会害得读者误解。

5.21. Lambda 表达式

适于使用 lambda 表明式。别用默许 lambda 捕获,全体捕获都要显式写出来。

定义:

拉姆da 表明式是创造无名函数对象的风度翩翩种简单渠道,常用于把函数当参数字传送,举例:

std::sort(v.begin(), v.end(), [](int x, int y) {
    return Weight(x) < Weight(y);
});

C++11 第一遍建议 拉姆das, 还提供了大器晚成多种管理函数对象的工具,譬喻多态包装器(polymorphic wrapper) std::function.

优点:

  • 传函数对象给 STL 算法,Lambdas 最简易,可读性也好。
  • Lambdas, std::functions 和 std::bind 可以搭配成通用回调机制(general purpose callback mechanism);写收到有界函数为参数的函数也十分轻巧了。

缺点:

  • Lambdas 的变量捕获略左道旁门,恐怕会引致悬空指针。
  • 拉姆das 或者会失控;层层嵌套的佚名函数难以阅读。

结论:

  • 按 format 小用 lambda 表明式怡情。
  • 剥夺暗中认可捕获,捕获都要显式写出来。打举个例子,比起 [=](int x) {return x + n;}, 您该写成 [n](int x) {return x + n;} 才对,那样读者能够一眼看出 n 是被捕获的值。
  • 无名氏函数始终要简单,尽管函数体超越了五行,那么还比不上起名(acgtyrant 注:即把 lambda 表明式赋值给目的),或改用函数。
  • 假使可读性更加好,就显式写出 lambd 的尾置重回类型,就好像auto.

5.4. 缺省参数

咱俩不准接收缺省函数参数,少数极端意况除了。尽可能改用函数重载。

优点:

当您有依据缺省参数的函数时,您大概有时会改过校勘那些缺省参数。通过缺省参数,不用再为个别意况而特意定义一大堆函数了。与函数重载相比较,缺省参数语法更为清晰,代码少,也很好地分别了「必选参数」和「可选参数」。

缺点:

缺省参数会振憾函数指针,害得前面一个的函数具名(function signature)往往对不上所实际要调用的函数具名。即在三个存世函数增添缺省参数,就能变动它的花色,那么调用其地方的代码大概会出错,可是函数重载就没那标题了。其它,缺省参数会促成丰腴的代码,究竟它们在每多少个调用点(call site)都有重复(acgtyrant 注:小编猜或许是因为调用函数的代码表面上看来省去了不菲参数,但编写翻译器在编写翻译时如故会在每二个调用代码里清一色补上全体暗许实参音信,变成大气的重新)。函数重载适逢其时相反,究竟它们所谓的「缺省参数」只会冒出在函数定义里。

结论:

鉴于后天不良并不是很严重,某一个人仍旧偏心缺省参数胜于函数重载。所以除了以下境况,大家渴求必须显式提供全数参数(acgtyrant 注:即无法再经过缺省参数来回顾参数了)。

其一,位于 .cc 文件里的静态函数或无名氏空间函数,终究都只幸而部分文件里调用该函数了。

那么些,能够在构造函数里用缺省参数,终归不恐怕拿到它们的地点。

其三,能够用来效仿变长数组。

// 通过空 AlphaNum 以支持四个形参
string StrCat(const AlphaNum &a,
              const AlphaNum &b = gEmptyAlphaNum,
              const AlphaNum &c = gEmptyAlphaNum,
              const AlphaNum &d = gEmptyAlphaNum);
上一篇:【新普京网站】编程风格指南,项目命名约定 下一篇:没有了