2、常量

目录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比较

  • 在编译阶段运行使用
  • 有具体的类型,在编译阶段要进行类型检查
  • const常量会在内存中分配内存,可是只是进行一次分配
  • 集成化的调试工具能够进行调试(这个不知道)
  • 能够定义局部常量,也能够定义全局常量(我以为能够用static,这个有待后面的搜集学习)

转别人的:

(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常量进行调试,可是不能对宏常量进行调试。
View Code

 

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成员的初始化:

  • 在类中,只有const修饰的常量,只能在构造函数的初始化列表进行初始化,类对应每一个对象的const的常量值能够不同
  • 在类中,有const 和static组合修饰,不能在构造函数初始化列表初始化,由于不属于对象。要在类外进行初始化,同时要加上const,不用加static。
  • 在函数内,const修饰的变量必须在声明的时候就进行初始化,且该变量再也不从新变。
  • 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 )
...
...
  • 这是由于非const变量默认为extern,可是const变量没有这个默认
  • 若是要const其余文件可以访问,要显示的指定为extern。固然,在其余地方使用的文件处,也须要加上extern,这个对于非const和const都是必须的。

 

2.五、 const引用

引用(reference)是对象的另一个名字,在对引用进行各类操做,也是对原始对象的各类操做。引用主要用做函数的行参。

引用是一种复合类型:用其余类型定义的类型。就是不能直接用常量定义。必定要关联到其余的类型。

不能定义引用类型的引用,可是能够定义任何其余类型的引用。

引用必须用其余类型初始化。必须初始化。

引用一旦绑定到一个对象,就不能再绑定到其余对象。

int iValue = 10;

int &rValue = iValue;//这个就是引用

const引用是指const对象的引用。

  • 既然是指向const对象的引用,const对象不能改变,其引用也不可以被改变。

   因此const对象的引用必须知足:一、若对象为const,则引用为const

   const int ival = 1024;

   const int &rval = ival;//这个引用就是指向const对象的引用,不能改变,由于rval与ival相关联,ival不能改变,其rval也不能改变,因此两个都必须为const。

  • 对象能够不为const,引用能够为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的对象的地址只能赋值给指向const对象的指针。若是赋值给指向非const对象的指针会出错,由于这个指针能够改变所指向的内容。
const double pi = 3.14;
double *ptr = π//错误,用指向非const对象的指针指向const对象
const double *cptr = π//这个是正确的为指向const对象的指针指向了const对象

不能用void*保存const对象的指针,必须用const void *保存const对象的指针。

  • 能够把非const对象的地址赋值给指向const对象的指针。
double dval = 3.14;
const double *cptr = &dval;

尽管dval不是const的,也不能经过cptr来改变dval的值,能够经过其余方式改变dval的值。

总结

  • 指向const对象的指针无论怎么样都不能改变本身所指向的对象。
  • 指向const对象的指针能够指向const对象,也能够指向非const对象。
  • 指向const对象的指针经常使用做函数的行参。确保传递给函数的实际对象在函数中不由于行参而被破坏
  • 所指向的基础对象不能改变,可是该指针能够改变,这个指针能够指向多个对象。

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

总结

  • 指向const对象的指针,指针可变,对象内容不可变,无论指向的对象是否是const,都不能经过指针来修改这个对象的内容
  • const指针,指针不可变,对象则根据对象的类型判断可变。

有一个须要注意:

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这个关键字。

相关文章
相关标签/搜索