《高质量C++/C编程指南》读书笔记--week 3

本次阅读的为本书的最后一部分。

第八章 C++函数的高级特性

8.3参数的缺省值:

函数的缺省值只能出现在函数的声明中,而不能出现在定义体中

如 void Foo(int x=0, int y=0);   正确。

而 void Foo(int x=0,int y=0) {……} 错误。

如果函数有多参数,参数只能从后向前挨个缺省,否则将会使函数调用语句奇怪。

8.4运算符重载

例如 Complex Add(const Complex &a, const Complex &b)可以用运算符重载为Complex operator +(const Complex &a, const Complex &b);

不能改变C++内部数据类型,如int,float,以及‘.’,#,@,$等,且对于已经存在的运算符进行重载时,不能改变优先级规则,否则将引起混乱。

8.5函数内联

C++中的函数内联对比于C语言中的宏代码,加入了类型安全检查或者进行自动类型转换,既具备宏代码的效率,又增加了安全性,而且还可以自由操作类的成员。

关键字inline必须与函数定义体放在一起才能使函数成为内联,仅将inline放在函数声明前面不起任何作用。且建议把inline仅仅放置在函数定义体前面。

内联是以代码膨胀为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率,所以如果执行函数体内代码的时间,相比于函数调用的开销较大,或者使程序总代码量增大很多,消耗更多的内存空间,特别是函数体内代码比较长,或者函数体内出现循环,那么不建议使用内联。

第九章 类的构造函数,析构函数与赋值函数

9.1 构造函数与析构函数的起源

C++语言中,把对象的初始化工作放在构造函数中,把清楚工作放在析构函数中。当对象被创建时,构造函数被自动执行。当对象消亡时,析构函数被自动执行。

构造函数与析构函数与类同名,且都没有返回值。但是析构函数与构造函数目的相反,因此加上前缀~以区别它们。  

9.2构造函数的初始化表

   构造函数有个特殊的初始化方式“初始化表达式表”,位于函数参数表之后,在函数体{}之前,即表里的初始化工作发生在函数体内的任何代码被执行之前。与此同时,const常量只能在初始化表里被初始化,类的数据成员的初始化可以采用初始化表或函体内赋值两种方式,这两种方式的效率不完全相同,非内部数据类型的成员对象应当采用第一钟方式初始化,以提高效率。

9.3构造和析构的次序:

构造从类层次的根处开始,在每一层中,先调用基类的构造函数,然后调用成员对象的构造函数。析构则是严格按照与构造相反的次序执行。

9.4拷贝函数与赋值函数:

拷贝函数是再对象被创建时调用,而赋值函数只能被已经存在了的对象调用。且使用拷贝函数时应宜写成string c(a)的形式,以区别赋值函数。同时也应该注意,编译器以“位拷贝”的方式自动生产缺省的函数,倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。赋值函数在函数入口处需要检查是否有自赋值的现象,以避免出现指针赋值时,把自己的内存释放了却继续复制自己的现象。

9.4派生类中类的基本函数:

基类的构造函数,析构函数,赋值函数都不能被派生类继承,如果类之前存在继承关系,则在派生类的构造函数中,应在其初始化表里调用基类的构造函数,基类与派生类的析构函数应该加上virtual关键字。在编写派生类的赋值函数时,要注意对基类的数据成员重新赋值。

第十章类的继承与组合

10.1继承:

如果A为基类,B为A的派生类,则B将继承A的数据和函数。这意味着,若类A与类B毫不相干,不可以为了使B的功能更多些而让B继承A的功能和属性。只有在逻辑上B为A的一种,并且A的所有功能和属性对B而言都有意义,则才允许B继承A的功能和属性。

10.2组合:

若在逻辑上A是B的一部分,则不允许B从A派生,而是应当用A和其他东西组合出B。如Eye,Nose,Mouth,Ear等为Head的一部分,此时不应该写为class Head:public Eye, public Nose ,public Mouth, public Ear 而是应当在类内部设置对象组合成这些功能。将Head直接派生虽然可以使程序简短并且正确运行,但是这种程序设计方法不对,不见得是高质量的程序。

第十一章其他编程经验

11.1 const的运用

  被const修饰的东西都受到强制保护,可以预防意外发生的变动,能提高程序的健壮性,建议在需要使用的时候就毫不犹豫使用。

①    用const修饰函数参数:若参数作输出作用,无论什么数据类型,都不能加const修饰。但const能修饰输入参数,如指针传递,引用传递,来解决不想改变的输入参数却在函数中被无意改动的情况。

②    用const修饰函数的返回值:如果用const修饰函数的返回值,那么函数的返回值的内容不能被修改。且若修饰的为指针传递方式的函数返回值,该返回值只能被赋给加了const修饰的同类型指针。若函数返回值用值传递方式,由于函数会把返回值复制到外部临时单元中,所以加const修饰没有任何价值。若函数返回值采用引用传递,则链式表达将会非法。

③    const成员函数:任何不会修改数据成员的函数都应该声明为const类型,即在函数声明后面加上const,使得不慎修改了数据成员时让编译器指出错误,以提高程序的健壮性。

11.2提高编程效率

①在满足正确性,可靠性,健壮性,可读性等质量因素的前提下,设法提高程序效率。

②以提高程序的全局效率为主,局部效率为辅。

④    在优化程序效率时,找出限制效率的瓶颈。先优化数据结构和算法,再优化执行代码。

⑤    正确选择时间效率与空间效率。

⑥    不追求紧凑的代码,紧凑的代码并不能产生高效的机器码。

11.3 一些有益的规范

①注意如==误写为=,||写为|,&&写为&等视觉上不易分辨的书写错误。

②变量被创建后应该及时初始化,注意变量的初值,缺省值,精度错误,上溢下溢,数组越界。尽量不使用与具体或者软件环境密切关联的变量。变量数据类型转换时,尽量用显式的数据类型转换,便于让程序员知道发生了什么。

③避免编写技巧性很高的代码,同时不要设计面面俱到,非常灵活的数据结构。将编译器的选项设置为最严格的状态

④尽量使用标准库函数,以及重复使用原有的质量比较好的代码,宁可重写也不修补很差劲的代码。

posted @ 2018-03-21 16:01  wispytrace  Views(126)  Comments(3)    收藏  举报