这几天看了下这本书《编写高质量代码_改善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. Ubuntu 16.04 64位安装arm-linux-gcc交叉编译器以及samba服务器

    交叉编译器是嵌入式开发的必要工具,但是由于目前大多数人使用64位ubuntu,在照着很多教程做的时候,就会失败,失败原因是64位ubuntu需要额外安装32位的兼容包.以arm-linux-gcc-3 ...

  2. Android开发(四)——Android中的颜色

    Android开发中关于资源文件的存储操作.对于Android资源也是非常重要的,主要包括文本字符串(strings).颜色(colors).数组(arrays).动画(anim).布局(layout ...

  3. [转]Bootstrap table后端分页(ssm版)

    原文地址:https://www.cnblogs.com/flyins/p/6752285.html 说明bootstrap table可以前端分页,也可以后端sql用limit分页.这里讲的是后端分 ...

  4. 【C#】使用NHibernate连接MySQL数据库及增删改查

    学习资料 http://www.sikiedu.com/course/51/task/891/show https://www.codeproject.com/Articles/26123/NHibe ...

  5. 关于OpenVR

    一直在期待一种大一统的开放的VR技术规范,虽然短期内这点明显是不太现实的.前几天在翻译Godot的开发进展#6那篇文章时,看到了一个词OpenVR,瞬间有感觉了. 从我的经历的技术规范演进版本来看,从 ...

  6. JavaScript cookie操作实现点赞功能

    JavaScript cookie操作实现点赞功能 参考实现原理,但是代码不够简洁,简洁代码参考:js操作cookie 实现一个点赞功能十分简单,主要问题在于不能重复点赞.  若是一个有用户的网站,可 ...

  7. 七牛图片存储api

    https://developer.qiniu.com/kodo 属于对象存储 https://www.qiniu.com/prices 如何获取存储文件的外链接 https://developer. ...

  8. 关于源码输出,浏览器不解析Html标签

    有时候根据需要我们需要看到浏览器上源码效果如: 但是我如果在html中输入 <a href = 'http://www.baidu.com'>百度</a>那么问题来了,总是显示 ...

  9. android sqlite blob

    BOLB表示二进制大对象,这种数据类型通过用来保存图片,图象,视频等. 使用场景: http://blog.sina.com.cn/s/blog_8cfbb99201012oqn.html publi ...

  10. C++标准 bind函数用法与C#简单实现

    在看C++标准程序库书中,看到bind1st,bind2nd及bind的用法,当时就有一种熟悉感,仔细想了下,是F#里提到的柯里化.下面是维基百科的解释:在计算机科学中,柯里化(英语:Currying ...