- 尽量以const,enum,inline替换#define
- 用宏定义一个常量的时候,可能会发生一些错误。当发生错误的时候你可能并不能知道这个错误具体出自哪里,因为宏定义的变量可能没有进入记号表中(symbol table)。还有就是宏定义的东西可能会盲目的置换代码中的变量(直接全部置换过去,括号可能会影响最终的结果),会导致出错。
- 当我们要定义一个常量去替换#define时,有两种情况
- ①定义一个指向常量的常量指针,可以这么定义:const std::string author(''fuzhiqiang'')
- ②定义一个class专属常量,#define不具有封装性,不能够定义class类的专属常量
- 枚举enum在很多地方和#define很像。他们都是不允许去得到他们的一个地址。而const取地址是合法的。
- 但是#ifdef和#ifndef控制编译功能十分重要
- 对于单纯的常量,最好用const或者enum;对于形似函数的宏最好用inline函数
- 尽可能使用const
- 指针使用const
- 常量指针:char* const pContent ,是一个指针,它指向的内容是不能变的,但是*pcontent可以改变,通过改变*pcontent可以改变它所指的值
- 指针常量:const char *pContent,指针所指向的内容是常量,不能改变,就是*pcontent不能改变,pcontent可以改变
- 指向常量的常量指针:const char* const pContent,都不能改变
- 函数使用const
- 参数为引用,为了增加效率同时防止修改。修饰引用参数时:
void function(const Class& Var); //引用参数在函数内不可以改变
void function(const TYPE& Var); //引用参数在函数内为常量不可变
这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性, 且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙.
- 参数为引用,为了增加效率同时防止修改。修饰引用参数时:
- 类使用const
- const修饰成员变量:修饰的成员变量不能被修改
- const修饰成员函数:const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。常成员函数, 它不改变对象的成员变量,也不能调用类中任何非const成员函数。
- 对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。
a. const成员函数不被允许修改它所在对象的任何一个数据成员。
b. const成员函数能够访问对象的const成员,而其他成员函数不可以。
- 将const类型转换为非const类型
- 用法:const_cast <type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
- 用法:const_cast <type_id> (expression)
- 建议
- 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
- 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
- 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
- const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
- 不要轻易的将函数的返回值类型定为const;
- 除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;
- 任何不会修改数据成员的函数都应该声明为const 类型。
- 指针使用const
- 确定对象在被使用前已经被初始化
- array的内容没有初始化,而vector的内容确是初始化了的
- 内置类型:bool,char,w_char,short,int,long,float,double,long double;这些初始化都手动完成
- 类的初始化:一般采用成员列表初始化,而不是单一的赋值
-
class myclass{ private: string Name; int Id; string Sex; public: myclass(cosnt string & name,cosnt int & id,const string & sex): Name(name),Id(id),Sex(sex){} };
- 这其中初始化的次序有讲究的:按照变量声明的次序来进行成员列表初始化
- 不同的编译单元内定义的 non-local static变量
- 这里先解释一下名词,static是静态的意思,表示这个变量不由栈分配,而存储在特有的全局变量/静态变量区域中,具有长寿命的特点(从被构造出来,直到程序结束时,才会由系统释放资源);而non-local则是说这个对象是全局的,而不是函数内的静态变量,是说它的作用范围广。
-
比如在文件1中定义了
int a = 1;
而在文件2中又会去使用:
extern int a; int b = a *3;
可以看到文件1应在文件2之后执行,这样a才能获得初值,否则b得到的将是垃圾值,但事实上C++对于不同文件执行的相对次序并无明确定义,这样b究竟得到的是垃圾值还是3就不能确定。
解决这个问题是方法是不要使变量有全局的作用域,可以在文件1中定义:
1 int& GetA() 2 { 3 static int a = 1; 4 return a; 5 }
而在文件2中调用
int b = GetA();
这样就一定保证a的初始化在先了。