1、让自己习惯c++

来源:互联网 发布:淘宝开店怎么挣钱 编辑:程序博客网 时间:2024/06/05 03:42

条款 2:尽量使用const、enum、inline替换#define

首先,由于#define是在预处理阶段对代码中的字符串进行替换,安全没有任何安全检查,而且一旦程序由于宏替换引发的任何错误,错误提示只会显示替换后的数值,根本无法找到具体的某个宏导致的错误。其次,#define并不重视作用域,一旦宏被定义,其后面的编译过程都有效(除非#undef),因此不提供任何封装性;最后,#define常用来实现类似于函数功能的宏,但不会有函数调用的时间开销。这样的宏必须要注意带上小括号,但是仍然带来不少麻烦,如下面代码所示:

<span style="font-family:SimHei;">#define CALL_WITH_MAX(a,b) f((a),(b))?(a):(b)int a = 5;int b = 0;CALL_WITH_MAX(++a,b);      //a被累加两次CALL_WITH_MAX(++a,b);      //a被累加一次</span>

所以必须记住:

1、对于单纯常量,最好以const对象或enum替换#define

2、类似于函数的宏,最后改用inline函数替换#define


条款3:尽可能使用const

const允许你指定一个语义约束,编译器会强制实施这项约束,它允许你告诉编译器和其他程序员某值应该保住不变。修饰变量时,注意const所在的位置,如修饰指针变量时,在星号的前后是表示不同的意思;修饰函数返回值时,令返回值为常量值,往往可以降低因客户错误而造成的意外,又不至于放弃安全性和高效性。如乘法运算的返回值,如果const则无法对乘积进行赋值操作,防止用户写出这样的代码:(a*b)=c。修饰参数时,除非有必要改动参数或local对象,否则应该声明为const;修饰成员函数时,有两个流行的概念:bitwise constness(physical constness)和logical constness。bitwise constness派认为成员函数只有在不更改对象的任何成员变量的时候才可以说是const,也就是不更改对象的任何一个bit。这种定义正是c++对常量性的定义,因此const成员函数不可以更改对象内的任何non-static成员变量。但是,许多成员函数虽然不十足具备const性质却能通过bitwise测试。如果一个更改了“指针所指物”的成员函数虽然不能算const,但是如果有指针(而非所指物)隶属于对象,那么称此函数为bitwise const不会引发编译器异议。如下所示:

const CTextBlock cctb("hello"); //声明一个常量对象char* pc = &cctb[0]; //调用const operator[]取得一个指针,指向cctb的数据*pc = 'J'; //现在cctb有了"Jello"这样的内容

该代码创建了一个常量对象并设置初值,而且只对它调用了const成员函数,但是终究还是改变了它的值。这就导致了所谓的logical constness。logical constness派主张一个const成员函数可以修改它处理的对象内的某些bits,但是只有在客户端侦测不出的情况下才得如此。利用c++的一个与const相关摆动场:mutable,mutable可以释放掉non-static成员变量的bitwise constness约束,即在const成员函数中可以修改mutable修饰的成员变量的值。


所以必须记住:

1、将某些东西声明为const可以帮助编译器侦测出错误的用法。const可施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体

2、编译器实施bitwise constness, 但是程序员在写程序的时候应该使用“逻辑上的常量性”

3、当const和non-const成员函数有着实质等价的实现的时候,令non-const版本调用const版本(多写几个类型转换操作),避免代码重复


条款4:确定对象在使用前已被初始化

在c++中,全局或静态变量总会自动初始化,但是对于局部变量可没有这样的“福利”。另外对于内置类型的局部变量不会自动初始化,但是对于STL中实现的vector、string、list等对象会自动初始化。对于种种情况最佳做法就是永远在使用对象之前将它初始化。至于内置类型以外的其他任何东西,初始化的责任落在了构造函数的身上,所以要确保每一个构造函数都对对象的每一个成员初始化。这里切记注意初始化和赋值的区别,一律采用初始化成员列表进行初始化操作,而不是在构造函数中进行赋值操作,效率会降低,因为相当于先调用默认构造函数构造成员变量,然后对其赋值,虽然这对于内置类型的成员变量来说,初始化和赋值差别不大,但是对于reference和const类型的内置类型同样要通过初始化成员列表进行初始化,所以简单的做法就是:总是使用初始化成员列表。c++有着十分固定的“成员初始化次序”:基类早于派生类,而class的成员变量总是按声明的次序被初始化。

对于跨编译单元使用对象初始化的问题,如果某个编译单元某个non-local static对象初始化动作使用了另一个编译单元的non-local static对象,它所用到的对象可能未被初始化。解决方案就是:将每个non-local static 对象搬到自己的专属函数中(在函数中将该对象声明为static),函数返回一个reference指向它所含的对象。然后用户直接调用这些函数,而不是直接使用这些对象。

所以必须记住:

1、为内置类型对象进行手动初始化,因为c++并不保证初始化它们

2、构造函数最好使用初始化成员列表,而不要在构造函数中使用赋值操作。初始化成员列表列出的成员变量顺序应该与声明顺序保持一致(因为初始化顺序是按照声明顺序)

3、为避免“跨编译单元带来的初始化顺序”问题,请用local static代替non-local static对象


1 0
原创粉丝点击