c/c++ const的详解
来源:互联网 发布:发票查询真伪软件 编辑:程序博客网 时间:2024/06/05 11:21
C/C++语言里const是常见的限定符,有必要深刻理解const。在不同的地方const有不同的意思:
- 修饰一个变量时表示对该变量只做一次赋值
- 当作参数传入一个函数时,告诉这个函数这个参数是只读的
- 当作函数的返回值时,告诉调用者返回的变量是只读的
- 修饰一个函数时(C++),告诉编译器这个函数内部不会修改(*this)内容
因此,const是程序员和编译器之间的一个约定。这个约定带来的好处有:
- 编译器会采取一些优化策略进行编译
- 编译器进行语法检查,有助于减少代码错误
- 增强了代码的可读性
- 符合design by contract实践
[const变量的申明和定义]
1. C语言里申明一个const变量的时候不需要赋值,而定义的时候需要:
file1.c:
const int a = 5; // 定义
file2.c:
extern const int a; // 申明
// 下面可以使用a啦
如果a的作用域不是当前文件,那么编译器会给这个简单变量分配内存(因为其他文件可能用extern来申明并引用这个变量)。如果用static修饰这个const变量,编译器可能直接优化掉它,而并不分配内存。
2. C++的类成员变量使用const的方法:在class的申明里使用const限定,然后在构造函数初始化。比如:
c++ const class data member:
class A {
public:
A();
private:
const int a; // 这个是申明
};
A::A() : a(5) // 设置初值的方法,不可以在ctor内部使用赋值的方式初始化
{
}
3. C++里的全局const变量的申明和定义方法
因为C++里的const全局变量作用域是属于本文件的(internallinkage),类似于加了static的限定,外部文件是不能访问的:
file1.cpp
const float faa = 3.5; // 这个变量其他文件无法访问。编译器甚至可以不分配内存
如果需要跨文件使用,在申明和定义的时候都需要加extern:
file1.cpp
extern const float faa = 3.5; //这个变量其他文件可以访问
file2.cpp
extern const float; // 这个是申明,不要赋初值
用nm可以查看const变量符号:
0000000100000f90 s __ZL3faa // 没有加extern的情况下。有的时候甚至看不到这个符号,因为被编译优化掉了
0000000100000f94 S _faa // 加了extern的情况下
[const和指针]
有3种组合形式:
const T *p; // p指向的内存的内容是const,p可以指向新的地址
T * const p; // p是const,也就是不能改变指向的地址,但是指向的地址的内容可以改变
const T * const p; // p是const,*p也是const
记忆的小窍门:如果const在*左边,则*p受const限制,也就是p指向的内存是不能改的;如果const在*右边,则仅仅p受const限制,即p指向哪里是不可更改的。
int m = 6;
const int n = 5;
const int *p1 = &n;
int * const p2 = &m; // p2的内容不是const,所以不要指向n
const int * const p3 = &n;
[const和nonconst]
从nonconst得到const的指针或者引用总是OK,因为只是放弃修改的权利。如果从const得到nonconst的指针或者引用,相当于要求写的权利。当你并没有显式的提出来,谨慎的编译器会给一个warning,提醒你是不是笔误啦?
int n = 5;
const int *p1 = &n; // no problem
int *p2 = p1; // warning
如果你觉得不是笔误,进行显式的转化,编译器也就不会说什么了:
int *p2 = (int *) &n; // OK
或者
int *p2 = (int *) p1; // OK
[C++的const_cast]
在C++里,增加了特别的语法const_cast用于得到non const的引用或者指针:
void foo(int a)
{
printf("a = %d\n", a);
}
int main()
{
const int a = 5;
int &b = const_cast<int &> (a);
foo(a);
return 0;
}
注意:不是改变原来的变量的const限定。语法:
outvar = const_cast<pointer or reference> (invar);
[const function]
在C++里,类的成员函数可以用const修饰:
class A {
public:
int foo() const {
printf("this is foo\n");
a = 5; // 编译error:不可以改变this的成员变量
return a;
}
int a;
};
这种const函数如果想改变某些成员变量,就需要把相关变量用mutable限定:
class A {
public:
int foo() const {
printf("this is foo\n");
a = 5; // 允许
return a;
}
mutable int a;
};
如果重载operator=,返回值不要用const限定(尽管语法正确),比如:
class A {
public:
const A&operator=(const A& in) {… }
};
原因是,返回的引用无法修改内容了,下面这种用法就编译不了:
A a, b, c;
(a = b) = c;
[constexpr]
C++11扩展了const,以前这种写法无法编译:
const int count()
{
return 5;
}
void bar()
{
char buf[count()] = {'a'}; // error: variable-sized object may not beinitialized
}
用constexpr就可以编译过去了,因为编译器可以在编译时确定出count()的返回值
constexpr int count()
{
return 5;
}
注意:
1. 很多编译器支持定义不定长数组(C99),比如:
void foo(int len) {
int a[len];
…
}
但是不允许给不定长的数组设置初始化数据。
2. C++11的编译方式:
例如:g++-std=c++11 main.cpp
[违反const约定]
1,通过指针修改const变量
编译器会检查const变量是否被改变:如果试图改变const变量的值,编译器会报错。但是如果程序员设置了指针指向该变量,仍然可以强行改变const变量的值,而编译器仅仅给个warning或者安静地pass过去了:
const int n = 5;
n = 6; // 编译error
int *p1 = &n; // 编译warning
int *p2 = (int *) &n; // OK
*p1 = 3; // OK
printf("n = %d\n", n); // 猜猜输出什么?
输出:
n = 5
可不是n= 3,意想不到吧?你欺骗了编译器,也要付出代价的!
内存里n确实被改成3了,但是编译器以为n是不变的,在printf语句里直接把n用5带入了,不会从内存里读取n的值。如果不是int这种简单类型,编译器不去优化这个变量的访问,那么这种通过指针进行修改const变量的方法还是有些用处的。
在有些情况下,通过指针的方式修改const变量不可行,比如:
const char *p = "a string";
这个字符串常量通常存放在代码段里,如果是在代码段存储的化,尝试修改会导致程序被kill。
2. const结构体的指针
一个结构体变量设置为const,其成员变量都是只读的。但是如果这个结构体包含成员指针变量,其指针指向的内容是不受保护的:
struct S { int val; int *ptr; };
void Foo(const S & s) {
int i = 42;
s.val = i; // Error: s is const, so val is aconst int
s.ptr = &i; // Error: s is const, so ptr is a const pointer to int
*s.ptr = i; // OK: the data pointed to by ptr is alwaysmutable,
// even though this is sometimes not desirable
}
- c/c++ const的详解
- C/C++static、const详解
- const用法详解 (C++)
- C语言const详解
- C语言const详解
- C/C++ const详解
- C/C++ const 详解
- C语言--const详解
- c/c++ const详解
- C:const 关键字详解
- C++中const详解
- 详解C++const关键字
- C++const详解
- C 语言的关键字 const详解
- C/C++中const详解
- C/C++中const详解
- C/C++中const详解
- c/c++中const详解
- 使用通知
- [转载]CSS3动画(360度旋转、旋转放大、放大、移动)
- 常见排序算法对比二(C++实现)
- 7月分布式项目遇到的错误及解决办法
- windows server 2003怎样开机不按Ctrl+Alt+Del进入系统
- c/c++ const的详解
- 微信扫码支付(模式一)遇到的那些坑
- C++中模板为什么不支持分离编译
- 度度熊的王国战略(最小割)
- JavaScript Boolean(逻辑)对象
- Jsp知识点之一
- spring boot中用RabbitMQ调用接口
- 那些年支付宝微信银联支付遇到的坑
- 《C++大数据运算(+、-、*、/)》