编写高质量代码_改善C++程序的150个建议 读书笔记
这几天看了下这本书《编写高质量代码_改善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个建议 读书笔记的更多相关文章
- 《编写高质量代码:改善Java程序的151个建议》笔记
To fight the unthinkable,you have to be willing to do the unthinkable. 不要在循环中使用try catch,应该放在循环的外面 ...
- 《编写高质量代码:改善Python程序的91个建议》读后感
编写高质量代码:改善Python程序的91个建议 http://book.douban.com/subject/25910544/ 1.(建议16)is 用于判断两个对象的id是否相等,==才是判断 ...
- 编写高质量代码:改善Java程序的151个建议(第二章:基本类型)
编写高质量代码:改善Java程序的151个建议(第二章:基本类型) 目录 建议21:用偶判断,不用奇判断 建议22:用整数类型处理货币 建议23:不要让类型默默转换 建议24:边界还是边界 建议25: ...
- 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)
编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...
- 《编写高质量代码:改善C#程序的157个建议》源码下载
==== 目录 前 言第一部分 语言篇第1章 基本语言要素 / 2建议1:正确操作字符串 / 2建议2:使用默认转型方法 / 6建议3:区别对待强制转型与as和is / 9建议4:TryParse比P ...
- 读《编写高质量代码:改善JavaScript程序的188个建议》1
建议3:减少全局变量污染 定义全局变量有3种方式: ❑在任何函数外面直接执行var语句. var f='value'; ❑直接添加一个属性到全局对象上.全局对象是所有全局变量的容器.在Web浏览器中, ...
- 读书笔记--《编写高质量代码:改善Python程序的91个建议》
第一章 引论 建议写Pythonic式的代码,我理解为充分利用pythonAPI,用最简洁方式写出代码 1.两个变量交换: a, b = b, a 2.翻转list: a = [1, 2, 3, ...
- 编写高质量代码:改善C#程序的157个建议
目录 前 言第一部分 语言篇第1章 基本语言要素 / 2建议1:正确操作字符串 / 2建议2:使用默认转型方法 / 6建议3:区别对待强制转型与as和is / 9建议4:TryParse比Parse好 ...
- 《编写高质量代码:改善JavaScript程序的188个建议》学习小记(二)
建议3:减少全局变量污染 1.把多个全局变量都追加在一个名称空间下,将显著降低与其他应用程序产生冲突的概率,应用程序也会变得更容易阅读. var My = {}; My.name = { " ...
随机推荐
- 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% ...
- Ubuntu 14.04快速搭建SVN服务器及日常使用
1.介绍 Subversion是一个自由,开源的版本控制系统,这个版本库就像一个普通的文件服务器,不同的是,它可以记录每一次文件和目录的修改情况.这样就可以很方面恢复到以前的版本,并可以查看数据更改 ...
- iOS全局变量的声明和使用
在一个项目中,我们可能需要定义几个全局变量,在我们程序的任何位置都可以进行访问,提高我们的开发效率.在iOS中我们如何来实现呢?我们主要使用的是AppDelegate类来实现.如下: (1)AppDe ...
- JDK 5.0 注解的使用
了解注解 在编写代码时,除了源程序以外,我们还会使用Javadoc标签对类.方法或成员变量进行注解,以便使用Javadoc工具生成和源代码配套的Javadoc文档. /** * 重写toString ...
- 【WPF/WAF】使用System.Windows.Interactivity交互事件
下载System.Windows.Interactivity.dll文件,并引入项目中(在VS项目的引用列表中可以看到).可在Nuget搜索System.Windows.Interactivity下载 ...
- JAVA是否可以作脚本语言呢
答:是可以的. 只是叫另一个名字-beanshell.印象里她好像还是第一款jvm语言.应该挺多年没更新了. 我之所以知道它,是当年折腾jEdit这款编辑器较多,它的内置脚本引擎使用的就是beansh ...
- 回顾:maven配置和常用命令整理
推荐两个库地址,开源中国的好像不好使了 阿里的仓库:http://maven.aliyun.com/nexus/content/groups/public/ 另一个:http://repo2.mave ...
- Eclipse启动都会Error when loading the SDK
http://jingyan.baidu.com/article/aa6a2c14fb54190d4c19c480.html
- ViewPager一屏显示多个item,及边缘滑动事件优化
关于ViewPager显示两边的item方法,网络上是方法都在ViewPager外包一个Layout, 然后设置ViewPager和外面的Layout的clipChildren="false ...
- 如何将baidu地图中的baidu logo 去掉
今天我的老大问我是不是可以将baidumap 的js版中baidu logo 去掉.我上网查询一下,有各种方法,比如将对应的logo div remove hide 等等,这些都是需要JS 函数触发执 ...