目录html
一、#define定义常量,好与坏数组
二、const关键字(各类const对象,指针,引用,函数,对应的引用等等)安全
常量就是在运行期间,值一直不变。c语言用#define定义,宏常量。C++里面用#define和const定义常量。ide
转:http://blog.csdn.net/love_gaohz/article/details/7567856函数
http://blog.sina.com.cn/s/blog_60be7ec80100gzhm.html工具
一、define定义常量学习
定义的是全局常量spa
define宏是在预处理阶段展开.net
没有类型,仅仅是展开,不作类型展开指针
仅仅是展开,多少个地方使用,就有多少个地方展开。(宏定义不分配内存,变量定义须要分配内存)
只是替换字符串,容易产生意想不到的错误(边际效益)
二、const常量
2.一、 const和define比较
转别人的:
(1) 编译器处理方式不一样 define宏是在预处理阶段展开。 const常量是编译运行阶段使用。 (2) 类型和安全检查不一样 define宏没有类型,不作任何类型检查,仅仅是展开。 const常量有具体的类型,在编译阶段会执行类型检查。 (3) 存储方式不一样 define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。) const常量会在内存中分配(能够是堆中也能够是栈中)。 (4)const 能够节省空间,避免没必要要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,之后再也不分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define同样给出的是当即数,因此,const定义的常量在程序运行过程当中只有一份拷贝(由于是全局的只读变量,存在静态区),而 #define定义的常量在内存中有若干个拷贝。 (5) 提升了效率。 编译器一般不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操做,使得它的效率也很高。 (6) 宏替换只做替换,不作计算,不作表达式求解; 宏预编译时就替换了,程序运行时,并不分配内存。 const 与 #define的比较 C++ 语言能够用const来定义常量,也能够用 #define来定义常量。可是前者比后者有更多的优势: (1) const常量有数据类型,而宏常量没有数据类型。编译器能够对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,而且在字符替换可能会产生意料不到的错误(边际效应)。 (2) 有些集成化的调试工具能够对const常量进行调试,可是不能对宏常量进行调试。
2.二、 C++中尽可能使用const,避免使用define
对外被使用的常量应放在头文件,内部使用的常量放在源文件的头部。
能够将常量都定义在一个文件里面便于管理
2.三、类中的const成员
const定义的常量在函数执行和对象销毁以后其空间会被释放。
对于类中的仅仅用const修饰的常量,相对于对象来讲是不变的,可是对于类来讲是变的。由于一个类能够建立不少对象,这样在进行构造函数初始化的时候,能够进行初始化。
因此在类声明const成员的时候,不能就直接给const常量进行赋值。
class Test{ public: const int size = 10;//error,不能在类声明中给const常量赋值 int array[size];//size未知
}
在类中,如何进行const赋值,只能经过构造函数的初始化列表进行赋值,并且还必须是在初始化列表里面进行初始化。这样的话就能够对于每个对象有不一样的const常量。
class Test{ public: const int size; Test(int s):size(s){ ... ... } };
那如何才能作到对于整个类来讲不变的常量,可使用:枚举,static const。
枚举:
class Test{ public: Test():constValue(9){} enum {size1 = 100, size2 = 200};//枚举 private: const int constValue;//这个是const常量,只能在构造函数的初始化列表里面进行初始化。 static int staticValue;//这个是静态变量。整个类可使用,只有一次初始化,能够改变值 const static int allValue;// static const is ok. 这个是静态常量 }; int Test::staticValue = 10;//不能在构造函数初始化列表初始化,不能在声明处初始化,由于不属于某个对象 const int Test::allValue = 10;//给静态变量赋值的时候,不用加static,上面的staticValue也没有加
总结:const成员的初始化:
2.四、const默认为文件的局部变量
const默认为文件的局部变量。
在全局做用域里定义非const变量,它在整个程序里面均可以进行访问。
//file_1.cc int counter; //定义 //file_2.cc extern int counter; //能够经过extern用counter ++counter;
可是对于在全局做用域声明的const变量是定义为该文件的局部变量。只存在于那个文件,不能被其余文件访问,若是但愿其余文件可以访问,必须在前面加上extern,这样,在整个程序中,均可以访问这个const变量。
//file_1.cc //const必须在声明的时候进行初始化(函数和全局变量) extern const int bufSize = fcn(); //file_2.cc extern const int bufSize;//能够在这个文件使用 if (int index = 0; index != bufSize; ++ index ) ... ...
2.五、 const引用
引用(reference)是对象的另一个名字,在对引用进行各类操做,也是对原始对象的各类操做。引用主要用做函数的行参。
引用是一种复合类型:用其余类型定义的类型。就是不能直接用常量定义。必定要关联到其余的类型。
不能定义引用类型的引用,可是能够定义任何其余类型的引用。
引用必须用其余类型初始化。必须初始化。
引用一旦绑定到一个对象,就不能再绑定到其余对象。
int iValue = 10;
int &rValue = iValue;//这个就是引用
const引用是指const对象的引用。
因此const对象的引用必须知足:一、若对象为const,则引用为const
const int ival = 1024;
const int &rval = ival;//这个引用就是指向const对象的引用,不能改变,由于rval与ival相关联,ival不能改变,其rval也不能改变,因此两个都必须为const。
int i = 42;
const int &r = 42;
const int &r2 = r + i;
或者
double dval = 3.14;
const int &ri = dval;
由于编译器会把代码转换为如下形式:
int temp = dval;
const int &ri = temp;
引用绑定到了ri上面。dval的改变不会影响到ri的值。
总结:
非const引用只能绑定到与该引用同类型的对象。
const引用的赋值能够绑定到:一、相同类型的const,非const对象。二、相关类型的const、非const对象。三、绑定到右值
利用const引用避免了赋值。
书上的话:若是使用引用行参的惟一目的是避免复制,则应定义为const
2.6 const与指针
这个比较复杂,并且很难记;const和指针的关系有两个:指向const对象的指针,const指针
2.6.1 指向const对象的指针
若是指针是指向const对象,则不容许用指针改变其所指的const值。
const double *cptr;//该为指向const对象的指针
const限定的是cptr指针所指的对象,并不是cptr指针,cptr并不具备const特性,因此在定义的时候并不须要进行初始化。能够对cptr进行从新赋值,便可以指向其余对象。可是不能同构cptr修改所指向的内容。
*cptr = 42;//错误的,不能改变所指向对象的内容
++cptr;//这个是对的,由于该指针没有const特性。
const double pi = 3.14; double *ptr = π//错误,用指向非const对象的指针指向const对象 const double *cptr = π//这个是正确的为指向const对象的指针指向了const对象
不能用void*保存const对象的指针,必须用const void *保存const对象的指针。
double dval = 3.14; const double *cptr = &dval;
尽管dval不是const的,也不能经过cptr来改变dval的值,能够经过其余方式改变dval的值。
总结:
2.6.2 const指针
const指针:指针不能更改,可是指针所指向的对象的值能够更改(若是对象不是const,能够更改,若是是const,则不能更改)。即这个指针只能指向一个对象,能够经过这个指针改变对象的值。
int errNumb = 0;
int *const curErr = &errNumb;
++curErr;//出错,由于指针不能更改
*curErr = 1;//对的
2.6.3 这两个很差记:
先忽略类型名,看const离哪一个近,就修饰谁;
const *p;//const修饰*p,p是指针,*p是指针指向的对象,不可变
*const p;//const修饰p,p不可变,p指向的对象可变。
const *const p;//前一个修饰*p,后一个修饰p
总结:
有一个须要注意:
string s;
typedef string *pstring;
const pstring cstr1 = &s;
pstring const cstr2 = &s;
string *const cstr3 = &s;
这三个都是同样的,都是:指向string类型对象的const指针
2.7 const参数,函数
const参数:对于参数在函数中不须要被改变,将参数定义为const是较好的选择,由于这样能够传递常量进来。
int strlen(const char* str);//这个就能够传递非const字符串,const字符串,以及"fjdajf"这种字符常量。若是没有const的话,则不能传递最后一种状况的字符串。前两种恰好验证了指向const对象的特性。
const函数:将函数定义为const,至关于修饰返回值,不可改变
int fun(void) const;
const差很少就这些吧。若是还有,之后再加。
写到这,忽然以为行参能够弄个专题:由于涉及到引用传递数组这个问题。还有volatile这个关键字。