您的位置:首页 > 运维架构 > Linux

linux c/c++ 学习总结(4)--const关键字

2018-06-22 15:38 197 查看

const这个关键字在c++被“重载”了很多次,写在不同地方表示不同的意思。需要分别来说明:

const 修饰变量

第一点:const修饰的变量一定要初始化,const变量的值在编译时就要被确定,放在“代码段”的“.rodata”中,如果在程序中显示的修改const变量,会报编译时错误,如果一些技巧来欺骗编译器来修改const变量,其行为是未定义的。例如:

int num = 90;               //定义非const变量
const int &r = num;          //使用const引用来指向num,此后就不能通过r来修改num了
const_cast<int &>(r) = 100;  //使用RTTI来去掉r的底层const,然后再来修改r,这样做是安全的因为num本来就是非const
cout<<num<<endl;            //输出num为100

//但是
const int num = 90;          //定义const变量
const int &r = num;          //使用const引用来指向num,此后就不能通过r来修改num了
const_cast<int &>(r) = 100;  //使用RTTI来去掉r的底层const,然后再来修改r,这样做行为是未定义的
cout<<num<<endl;             //输出会发现num依然为90,c++承诺常量始终是常量

第二点:const变量的连接性是内部的。在头文件中定义一个非const变量(如 int num = 10;),由于头文件可能会被多个实现文件包含,这个“num”变量是一个全局变量,它是一个强符号,链接器会报重复定义,有趣的是被const修饰的变量却不会,原因是const变量的连接性是内部的,它的作用域和static一样会被限制在当前翻译单元中,这种连接性为内部的变量,在编译时就被初始化了,不需要等到运行时(const变量的初始化可以被推迟到运行时,后面介绍)。

底层const与顶层const

const在修饰指针变量和引用时会有顶层底层之分,看代码

int num = 90;
int * const p = &num;   //此时的p是带有顶层const的,它表示p是一个常量,因此必须初始化
int const * p = &num;   //此时的p是带有底层const的,它表示不能通过p来修改num,而不管num本身是否为常量。
const int  * p = &num;   //这种写法等价于上面的

int num = 90;
int const & r = num;   //此时的p是带有底层const的,它表示不能通过p来修改num,而不管num本身是否为常量。
const int  & r = num;   //这种写法等价于上面的
int  & const r = num;   //错误,没有这种写法

//关于为什么没有上述写法,我的理解是引用的本质是一个“自解引用的常量指针”,如
int &r = a;         //等价于 int *const r = &a;  这也是为什么引用必须初始化的原因
cout<<a<<endl;      //等价于 cout<<*a<<endl;
//当然上述对引用本质的理解是从编译器角度来说的,还可以从单纯的概念层面来说明问题,今后会写一篇我对引用理解的文章。

const与constexpr及常量表达式

第一点:先说说什么是常量表达式:常量表达式是在编译时就能确定其值且在运行时不会改变的量,一个变量是不是常量表达式由其变量类型和初始值决定。

int num  = 1;//不是
const int num = 1;//是
const int num = size();//不是,const修饰的变量可以在编译时初始化,也可以推迟到运行时

第二点:c++11引入了constexpr,被constexpr修饰的变量或函数必须在编译时计算出来,看代码

constexpr int num = size();        //size()必须为constexpr函数
//constexpr函数是一个隐式inline函数,还要求该函数的参数和返回值只能是字面值,不能是虚函数,不能是递归函数

第三点:constexpr与指针

cosntexpr int * p = &num;        //constexpr是顶层的
int * const p = &num;            //等价于上面的

constexpr const int * p = &num;
const int * const p = &num;        //等价于上面的
//注意:由于constexpr的变量是一个在编译时确定的常量表达式,因此num必须有固定的地址,如全局变量和static变量。

const与函数重载

顶层const不能构成重载的依据,但底层const可以构成重载的依据,例如

void show(int num);
void show(const int num);   //顶层const,这两个不是重载

void show(int * p);
void show(int *const p);   //顶层const,这两个不是重载

void show(int & r);
void show(const int &r);   //底层const,是重载

void show(int *p);
void show(const int *p);  //底层const,是重载

//另外
void show();
void show()const;   //可以重载

在类中使用const

当我们在类中声明const成员变量时,变量一定要初始化。我们需要在类的构造函数的初始化列表中初始化,不能在函数体中初始化(因为函数体是在对变量赋值,而不是赋值)。还需要注意的是:由于通过构造函数可以把该变量初始化成不同的值,使得不同对象之间的值不同(这可能不是我们所想的),所以可以采用匿名enum类型定义常量。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: