02:尽量用const,enum,inline替换define
(一)【忠告】
a) 对于常量,用const和enum代替define
b) 对于形似函数,用inline代替define
(二)尽量替换掉define的原因:
a) define A 1.63出错时,报1.63出错;const int A=1.63出错时,报A出错。显然报变量名出错更加容易调试
b) define的可见范围不可控制,const修饰的常量可以被类封装
(三)常量替换define的两种特殊情况:
a) 当常量定义成指针时,要有两个const,即const int* const A=10;前一个const保证了指针A指向地址的内容不会发生变化,后一个const保证了指针A是个常量指针(*const A:常量指针),它指向的地址不会发生变化。
b) Class的专属常量
i. Class AAA{
Private:
Static const int num=10;
Data[num];};
支持静态变量内初始化的编译器可以这么干。
ii. Class AAA{
Private:
Static const int num;
Data[num];};
AAA::num=10;
不支持内初始化的编译器只能这么干,但这时候,Data数组就不知道大小,编译会出错
iii. Class{
Private:
enum{num=10};
Data[num];};
枚举中的常量可以被类成员直接引用。这样就避免了不支持静态变量初始化的编译器,无法实现上述做法的问题。并且enum不会被取到常量地址,如果不想被取到常量地址,也可以这么做。
(四)补习枚举类型enum:
a) 定义enum Luo{a=’a’,b,c,d,e,f,g};
b) Luo是像int那样的类型名。enum Luo中的a,b,c都是常量,且在程序中可以直接使用a来表示’a’。enum的大小为4字节,由编译器决定,不以常量个数而变化。
c) 使用示例
int main(){
enum A{a='a',b,c,d,e,f,g,h,i,j,k};
cout<<sizeof(A)<< a <<endl;//4;97(‘a’的ascii值)表示可以直接用
A test;test = (A)9;
cout << test << endl;}
条款03:尽可能使用const
(一)【忠告】
a) Const可以被用来修饰任何作用域内的对象、变量(成员变量)、函数返回值(成员函数返回值)、函数参数(成员函数参数)、函数本身(成员函数本身)
b) 有些东西(比如返回值)声明为const,更容易排错
c) 可以使用mutable来释放编译器的bitwise-constness
d) 当const和non-const的实现没有什么区别时,可以用non-const来调用const的方法,使代码复用
(二)Const与指针
a) const int *A、const * int A、int * const A
i. Const在*的右边:表示指针A本身不是常量,指针A指向的地址可变,但地址中的内容物不可变
ii. Const在*的左边:表示指针A本身是常量,指针A指向的地址不可变,但地址中的内容物可变
b) 指针作为全局变量,放在头文件中时
i. 用Const int * const A=5;表示指针指向地址不可变,且地址中的内容物亦不可变
(三)Const与迭代器
a) Const vector<int>::iterator it:表示迭代器本身是常量,不允许++it
b) Vector<int>::const_iterator it:表示迭代器所指向的地址内容不允许改变
(四)Const与类
a) Const修饰对象
i. Const对象被限制为只能调用const修饰的成员函数,因为non-const可能会改变对象的值
b) Const修饰成员变量
i. 和const修饰普通变量一样
c) Const修饰成员函数的参数
i. 和const修饰普通变量一样
d) Const修饰成员函数返回值
i. 可以帮助编译器排错:If(a*b=c){··· }//经常少打一个=,当非const时,且a和b均为某函数的返回值(对象),这个赋值动作就会被执行。但如果是const的话,那么因为常量不可被赋值,所以会报错,更容易排错了
ii. 如果函数返回值采用“值传递方式”【非引用,非指针】,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值。所以,对于值传递来说,加const没有太多意义。
e) Const修饰成员函数本身
i. 成员函数可以凭借有无const修饰来重载。Const一个版本、non-const又是另一个版本
ii. Const修饰成员函数,该成员函数不能更改任何non-static的成员变量,但可以使用mutable(修饰成员变量)来打破这个限制
iii. 当const和non-const成员函数相同时,non-const版调用const版可以代码复用
条款04:确定对象被使用前已被初始化
(一)【忠告】
a) 内置类型需要手工初始化。
b) 其他类型初始化,由构造函数承担。
i. 构造函数初始化最好用初始化列表。比起在构造函数中在赋实参值初始化,初始化列表1.成员变量不用先被赋上随机值;2.实参赋值给成员变量又是一次copy;3.形参到实参又是一次拷贝
ii. 初始化列表初始化顺序至于成员变量的声明顺序有关。
iii. Const和reference定义时需要初始化的成员变量,需要在初始化列表中初始化。Static需要在类体外初始化(如果编译器支持内初始化,那么可以在定义时就初始化)