1. const有什么用途?
在 c程序中,const的用法主要有定义常量、修饰函数参数、修饰函数返回值等3个用处。
在c++程序中,它还可以修饰函数的定义体,定义类中某个成员为常态函数,即不改变类中的数据成员。
被const修改的东西都要受到强制保护,可以预防意外的变动,能提高程序的健壮性。
2. const与#define相比有什么不同?
它们都可以用来定义常量,但const比#define有更多优点:
(1) const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。
(2) 在c++中使用const常量而不使用宏常量,即const常量完全取代宏常量。
注解:c++编译器中,可以通过指针强转改变,也可以通过当然也可以const_cast去掉const(只读)属性。
#include <iostream>
using namespace std;
int a = 5;
const int l = a;
int main(){
int *c = (int *)&l;
*c = 100;
cout<<l<<endl;
return 0;
}
结果是 100;
如果是下面这个:
#include <iostream>
using namespace std;
const int l = 5;
int main(){
int *c = (int *)&l;
*c = 100;
cout<<l<<endl;
return 0;
}
<div><img src="file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\598144530\QQ\WinTemp\RichOle\N}$[`5A51[FS)R)9ACRWJ@4.png" alt="" /></div>
const只是在编译期的保护,编译器会检查const变量有没有被修改,如果有代码尝试修改一个const变量,编译器会报错。但是你总是可以通过直接访问地址的形式去修改它的值。取决于编译器的不同,它有可能被放在某种被操作系统保护的区域内,尝试写入会导致程序崩溃之类的错误。
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。所以我们要大胆的使用。
当然,c++11也为我们引进了一个新的东西constexpr,constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。其作用相当于static const。不过安全性更高。
constexpr的好处:
- 是一种很强的约束,更好地保证程序的正确语义不被破坏。
- 编译器可以在编译期对constexpr的代码进行非常大的优化,比如将用到的constexpr表达式都直接替换成最终结果等。
- 相比宏来说,没有额外的开销,但更安全可靠。
const总结:
一、常量
#define PI 3.1415926
const double PI = 3.1415926
用const修饰保证会对他进行类型识别等必要的编译器内部操作,比宏定义更合理, 但要注意,声明时必须初始化,特别是在类类型中,要记得在初始化列表中初始化。(详见effective C++)
二、与指针联系
1、const int *p;
p是指向const int的指针,所以不能用赋值语句对*p赋值;但可以对p本身赋值。
2、int * const p=&i;
p是指向int的const指针。p是const数据,所以其本身不可改变,而*p可以被赋值。
(注意和const int *p;的区别。)p被初始化为i的地址,i是变量,这是*p可赋值的原因。
3、const int * const p=&i;
p是一个const指针,其指向const数据i。p、*p都不能再被赋值。
可以在初始化p指针时对其初始化。
三、与函数联系
1、普通函数
放在返回值前修饰返回值表示返回值必须保持其常量性,不能被更改;
放在参数前修饰参数表示该参数必须保持其常量性,不能在函数体内被修改;
2、类成员函数
放在函数尾部,表示其在函数内并不修改对象的属性,只是读取等操作非更易型操作
(当然声明类成员为易变类型另当别论) (详见TCPL)
四、与类型联系
当类的对象被声明成const类型后,它将不能调用更易型操作,所以很多成员函数有重载了的const版本
个人使用心得:
1. 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2. 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3.在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4.const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5.不要轻易的将函数的返回值类型定为const;
6.除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;
7.任何不会修改数据成员的函数都应该声明为const 类型。