这几天看了下这本书《编写高质量代码_改善C++程序的150个建议》,觉的蛮有收获的,再次记录下自己以前不清晰的知识点,以供学习。

编写符合标准的main函数

C语言标准规定了main函数的两种标准形式:


int main(void) int main(int argc, char* argv[])

C++03标准中给出了两种main函数的定义方式


int main() int main(int argc, char *argv[])

上述标准都要求main函数返回一个整型数值

extern C的作用

extern C的作用是当程序被C++编译器编译时,让后续的链接器以C方式来寻找函数,方便C++程序调用C程序。

注释风格

C++风格注释形如:// ....,推荐使用这样的注释。但是,头文件说明和函数默认参数的注释,还是用C风格(/**/)的较好。

不要写与编译器依赖紧密的代码

例如:printf("a %d %d", p(), q()),p和 q函数的执行前后顺序与编译器实现相关,应当避免此类代码。类似的还有 c = p() * q() * r()

尽量用const,enum,inline代替#define

inline关键字用在函数调用展开,在类声明中定义并且实现的函数自动为内联函数。如果需要将其他函数定义为内联函数,则需要在函数实现头声明此关键字,才让编译器尝试去内联,至于具体是否内联,还要求函数体满足一定条件才行,总体原则是短小精悍。

在使用define的场合,注意用()来保护宏函数。例如:#define MAX(a, b) ((a) > (b) ? (a) : (b))

struct在C和C++下的异同

C语言的struct不允许定义函数程序,而C++语言下的struct可以。

成员初始化

const成员变量只能通过"成员初始化列表"来进行初始化。在C++中允许声明一个函数但不无函数体实现。

类中成员变量如果是自定义类型,那么它的构造是先于类本身的构造函数,其构造顺序与在类中定义的顺序一致。

RAII手法:将资源的申请和释放操作包裹到类中的构造和析构函数中,隐式地保护资源。

所有数据成员一律为private类型。如果派生类需要用到,那么在用到的时候再将其改为protect类型,否则,一律声明为private类型,对外隐藏。

在具体声明时,可以按类型来多段声明,比如私有控件,来一个private,私有数据来另外一个private。

派生类初始化

在继承体系中,对象的构造是从最根处开始的。

虚函数相关

当类中至少包含一个虚函数时,才需要将其析构函数设置为虚函数。

在派生类被正确地构造出来之前,调用派生类的虚函数是没有意义的。

不要在构造/析构函数中调用虚函数。

虚函数需要配合继承机制,它生效于运行期,属于OOP范畴,适用于接口相同,逻辑不同的代码应用于不同的场合,实现了接口与实现的分离。

在C++中,还有一种成为pimpl idiom的手法,来更加彻底的分离接口和实现,大体实习思路是将对象中全部的数据成员封装在另一个实现类中,在本类中通过类成员指针或者是智能指针来引用。对外暴露的接口在内部都转发给实现类处理。

模板在编译器生效,它的本意是让不同类型的数据作用在相同的代码逻辑,属于GP范畴,体现为算法的普适性。

基类中虚函数的保护级别:

  • protect:标明派生类一定要重写该虚函数
  • private:标明派生类可以修改基类虚函数,如果无特殊要求的话,可以复用基类虚函数
  • public:禁止将虚函数声明为public权限

接口设计

设计目标:能覆盖完整功能并且达到接口最小化

以行为为中心的类设计,对外的public函数放在前面,需要继承的protect虚函数紧随其后,再后面是private的虚函数、普通函数以及成员变量。

语法的背后含义是语义,接口设计要有明确的语义,不可模棱两可、职责不清。

拷贝相关

如果类中无动态分配的资源类型,那么默认的浅拷贝可以满足要求。一旦有指针类型,那么,就必定有动态申请的资源,在拷贝时,需要重写赋值运算符,在目标类中重新申请空间,并且将原动态资源内容原封不动的拷贝过来。

如果重写派生类的赋值操作符,那么需要调用基类的赋值操作符,完整的进行赋值,而不是只赋值派生类数据,不赋值基类数据。

一般,只有在类宏成员变量动态申请了资源,才需要重写赋值操作符和拷贝构造函数。考虑到A = A这种情况,还需要重写==操作符,一般来说,重写的==,那么!=也顺带写上,保持相关操作的一致性。


A& A::operator=(const A& rhs) {
if(this == &rhs)
return *this; parent::operator=(rhs) // 派生类成员赋值 return *this; }

重载相关

overloading:具有相同函数名,但是不同参数形式的函数集合

overriding:在类中,派生类重写基类提供的虚函数,建议使用 override关键字来声明,在派生类中,不要用virtual来标明此为虚函数。

Hiding:派生类中重写和基类一样签名的非虚函数

模板相关

模板的声明和定义需要放在同一个头文件中,如果分离声明和实现,则外部在使用时,需要包含实现的cpp文件,这违反惯用法。

.inl文件可以将模板头文件和复杂模板定义分离,一般将其在头文件尾部进行包含。

异常相关

如底层发生异常,则需要逐级上报,直到有能力处理此异常的层级来处理。如果程序都没处理,则会被C++系统捕获并终止程序运行。异常可以将发生错误和处理错误分离。

一般以传值来抛出异常,以 const 引用来捕获异常,不涉及到异常对象的清理工作,无对象切割问题,如本层级处理后还需要继续抛出异常,可调用throw来。

智能指针

优先使用shared_ptr,它内部工作原理是引用计数,线程安全,支持扩展,推荐使用。

不要在stl容器中存储auto_ptr对象,因为容器元素是允许拷贝构造和赋值的,而auto_ptr是不能满足这一条件的。

STL相关

多用算法调用,少用手写循环。

杂项优化

不要返回局部变量的引用。

双重循环时,短循环放在外面,长循环放在里面。

优化常规框架:profiling --> 算法 --> 数据结构 --> 实现细节。

代码的主要功能是供给别人阅读,其次才是让编译器编译,让计算机执行,除了修改代码外,还有很多不用修改代码就能带来的优化,作为一个有追求的程序员,多了解代码之外的优化和设计方法是很有必要的。

编写高质量代码_改善C++程序的150个建议 读书笔记的更多相关文章

  1. 《编写高质量代码:改善Java程序的151个建议》笔记

    To fight the unthinkable,you have to be willing to do the unthinkable.   不要在循环中使用try catch,应该放在循环的外面 ...

  2. 《编写高质量代码:改善Python程序的91个建议》读后感

    编写高质量代码:改善Python程序的91个建议  http://book.douban.com/subject/25910544/ 1.(建议16)is 用于判断两个对象的id是否相等,==才是判断 ...

  3. 编写高质量代码:改善Java程序的151个建议(第二章:基本类型)

    编写高质量代码:改善Java程序的151个建议(第二章:基本类型) 目录 建议21:用偶判断,不用奇判断 建议22:用整数类型处理货币 建议23:不要让类型默默转换 建议24:边界还是边界 建议25: ...

  4. 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)

    编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...

  5. 《编写高质量代码:改善C#程序的157个建议》源码下载

    ==== 目录 前 言第一部分 语言篇第1章 基本语言要素 / 2建议1:正确操作字符串 / 2建议2:使用默认转型方法 / 6建议3:区别对待强制转型与as和is / 9建议4:TryParse比P ...

  6. 读《编写高质量代码:改善JavaScript程序的188个建议》1

    建议3:减少全局变量污染 定义全局变量有3种方式: ❑在任何函数外面直接执行var语句. var f='value'; ❑直接添加一个属性到全局对象上.全局对象是所有全局变量的容器.在Web浏览器中, ...

  7. 读书笔记--《编写高质量代码:改善Python程序的91个建议》

      第一章 引论 建议写Pythonic式的代码,我理解为充分利用pythonAPI,用最简洁方式写出代码 1.两个变量交换: a, b = b, a 2.翻转list: a = [1, 2, 3, ...

  8. 编写高质量代码:改善C#程序的157个建议

    目录 前 言第一部分 语言篇第1章 基本语言要素 / 2建议1:正确操作字符串 / 2建议2:使用默认转型方法 / 6建议3:区别对待强制转型与as和is / 9建议4:TryParse比Parse好 ...

  9. 《编写高质量代码:改善JavaScript程序的188个建议》学习小记(二)

    建议3:减少全局变量污染 1.把多个全局变量都追加在一个名称空间下,将显著降低与其他应用程序产生冲突的概率,应用程序也会变得更容易阅读. var My = {}; My.name = { " ...

随机推荐

  1. nginx动态配置及服务发现那些事

    Reference: http://xiaorui.cc/2016/10/16/nginx%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE%E5%8F%8A%E6%9C%8D% ...

  2. Ubuntu 14.04快速搭建SVN服务器及日常使用

    1.介绍  Subversion是一个自由,开源的版本控制系统,这个版本库就像一个普通的文件服务器,不同的是,它可以记录每一次文件和目录的修改情况.这样就可以很方面恢复到以前的版本,并可以查看数据更改 ...

  3. iOS全局变量的声明和使用

    在一个项目中,我们可能需要定义几个全局变量,在我们程序的任何位置都可以进行访问,提高我们的开发效率.在iOS中我们如何来实现呢?我们主要使用的是AppDelegate类来实现.如下: (1)AppDe ...

  4. JDK 5.0 注解的使用

    了解注解 在编写代码时,除了源程序以外,我们还会使用Javadoc标签对类.方法或成员变量进行注解,以便使用Javadoc工具生成和源代码配套的Javadoc文档. /** * 重写toString ...

  5. 【WPF/WAF】使用System.Windows.Interactivity交互事件

    下载System.Windows.Interactivity.dll文件,并引入项目中(在VS项目的引用列表中可以看到).可在Nuget搜索System.Windows.Interactivity下载 ...

  6. JAVA是否可以作脚本语言呢

    答:是可以的. 只是叫另一个名字-beanshell.印象里她好像还是第一款jvm语言.应该挺多年没更新了. 我之所以知道它,是当年折腾jEdit这款编辑器较多,它的内置脚本引擎使用的就是beansh ...

  7. 回顾:maven配置和常用命令整理

    推荐两个库地址,开源中国的好像不好使了 阿里的仓库:http://maven.aliyun.com/nexus/content/groups/public/ 另一个:http://repo2.mave ...

  8. Eclipse启动都会Error when loading the SDK

    http://jingyan.baidu.com/article/aa6a2c14fb54190d4c19c480.html

  9. ViewPager一屏显示多个item,及边缘滑动事件优化

    关于ViewPager显示两边的item方法,网络上是方法都在ViewPager外包一个Layout, 然后设置ViewPager和外面的Layout的clipChildren="false ...

  10. 如何将baidu地图中的baidu logo 去掉

    今天我的老大问我是不是可以将baidumap 的js版中baidu logo 去掉.我上网查询一下,有各种方法,比如将对应的logo div remove hide 等等,这些都是需要JS 函数触发执 ...