linux c/c++ 学习总结(4)--const关键字
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 = # //constexpr是顶层的 int * const p = # //等价于上面的 constexpr const int * p = # const int * const p = # //等价于上面的 //注意:由于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类型定义常量。
阅读更多- imooc 学习总结——离港篇:C++之const关键字
- C++学习小记之static和const关键字
- C++中const关键字的使用方法,烦透了一遍一遍的搜,总结一下,加深印象!!!
- C++ const关键字 总结
- C/C++中static,const,inline三种关键字详细总结
- C++ const关键字 总结
- C/C++中static,const,inline三种关键字的总结(参照网络)
- C++学习之路—const用法总结
- C++和C语言const区别关键字总结
- 【C/C++学习】const关键字的理解
- c++中const关键字总结
- C++学习笔记7,const关键字的使用(一)。
- C++学习笔记---const 关键字
- C++中const关键字的使用总结
- C++学习——const成员函数总结
- C++ const 关键字的简单总结
- 【C++学习】const的全面总结
- C++中Const关键字总结
- C/C++日常学习总结(第一篇)const用法及printf的执行顺序
- C/C++ const关键字用法总结