详解const限定符

const限定符

const对象

有时候我们需要定义一个值不可改变的变量,这时候我们就可以使用const来修饰这个变量(最用使用const变量而不是宏)。
const对象一经创建后就不可改变其值,所以它必须初始化

const int money = 1024;//定义money为常量——常变量,不可修改它的值。
money = 2048;// error: assignment of read-only variable 'money'

当有指针或者引用指向const对象时,会产生一个临时对象,这样指针或引用就不会改变const常量的值了。
例1
优秀的编译器一般不会为"整数型const对象"设置另外的存储空间(除非使用pointer或reference指向它)。至于具体如何来做取决于编译器的实现。

#include <iostream>
using namespace std;

int main()
{  
    const int money = 9;
    cout << hex << &money << endl;//取的是临时对象的地址
    
    int *p = (int*)&money;
    *p = 1;//改变的是临时对象
    cout << hex << p << endl;
    cout << "money = " << money << "    *p = " << *p << endl;
    
    int &r = const_cast<int&>(money);
    r = 2;//改变的是临时对象
    cout << hex << &r << endl;
    cout << "money = " << money << "     r = " << r << endl;
    
    cout << "*p = " << *p << "         r = " << r << endl;
    return 0;
}

执行结果:
在这里插入图片描述
示意图
在这里插入图片描述
测试编译器对const的做法

环境配置:Linux kali 4.9.0-kali3-amd64 #1 SMP Debian 4.9.18-1kali1 (2017-04-04) x86_64 GNU/Linux
g++ (Debian 6.3.0-12) 6.3.0 20170406
为了方便大家看,只贴出最核心的代码

//const1.cc
int main()
{
	int a = 666;
	return 0;
}

编译指令:g++ -S const.cc

 main:  
    pushq   %rbp
    movq    %rsp, %rbp
    ;为a分配内存
    movl    $666, -4(%rbp)
    movl    $0, %eax
    popq    %rbp
    ret
//const2.cc
int main()
{
	const int a = 666;
	return 0;
}
main:
    pushq   %rbp     
    movq    %rsp, %rbp   
    ;为a分配内存
    movl    $666, -4(%rbp)
    movl    $0, %eax
    popq    %rbp   
    ret

出乎意料之外,编译器的做法居然一样的。编译器为const常量分配了内存。
我们再来看一个案例:

//const3.cc
int main()
{
	const int a = 6;
	int *p = (int*)&a;
	*p =  777;
	
	int m = a;
	return 0;
}
main: 
    pushq   %rbp     
    movq    %rsp, %rbp  
    ;为a分配内存(临时对象)
    movl    $6, -16(%rbp)
    leaq    -16(%rbp), %rax
    ;为p分配内存
    movq    %rax, -8(%rbp)
    ;将a的地址传给 %rax
    movq    -8(%rbp), %rax
    ;将 777 赋值给 *p
    movl    $777, (%rax)
    ;关键是这一句,为m分配内存,其值直接为 6 而不是引用那个分配的临时对象中的值
    ;所以再怎么改,都不会影响其值,因为压根引用的不是它。
    movl    $6, -12(%rbp)
    movl    $0, %eax
    popq    %rbp   
    ret

总结来说,编译器对文件出现的 const变量的地方都替换成了对应的值。若是有引用或指针对它进行引用则编译器会生成一个临时对象让指针或引用去引用。
默认状态下const对象仅在文件有效。即

//test1.cc
const int a = 10;

//test2.cc
const int a = 20;
//在这两个文件中虽然同名但是它们都是独立的相互不影响。
//若要在多文件之间共享const对象,则需要在变量的定义之前添加extern关键字。
//在声明和定义时都添加extern关键字即可

//file1.cc
extern int bufSize = fcn();
//file1.h头文件中
extern const int bufSize;//与file1.cc中的是同一个。

const与指针

const在*号的左侧

//int const* p1;//等价于下面的写法,推荐下面的写法
int x = 666;
int y = 777;
const int* p1 = &x;//point to constant objects    
//即指向的对象不可变,换句话说只可以读你所指的对象,但是能更改它。
p1 = &y;//OK
*p1 = 888;//error,不可以更改指向的对象

在这里插入图片描述
const在*号的右侧

int i = 11;
int j = 22;
int * const p2 = &i;//a constant pointer point to objects
//指针指向不可更改(只读),但是可以改变指向的对象
*p2 = 33;//OK
p2 = &j;//error,指向不可以改变

在这里插入图片描述
const在*号的左右两侧

//不说你也猜到了,它就是上面两种的综合,它既不可以更改指针的指向,
//又不可以更改指针指向的对象。
int m = 1;
int n = 2;
const int * const p3 = &m;
*p3 = 666;//error,不可更改指向的对象
p3 = &n;//error,不可更改指向

const与引用

阅读另一篇博客:https://blog.csdn.net/Marshalldong/article/details/88062969

const成员函数

const修饰成员函数的本质其实是修饰this指针。const与指针参见上文。
看一个例子

class Str{
public:
	Str(char c):ref(c)
	{}
	char& get() const
	{
		return ref;
	}
private:
	char &ref;
};

Str s('a');
char &c = s.get();
c = 'd';
/*
c修改了其内部的private的data-member, 
虽然我们为成员函数加了const,表示不可修改其成员,但是由于返回了引用,导致外部可以修改内部成员。这显然不是我们想看到的,如不要这么做就得在函数返回值上加const限定
*/

//修改get函数返回值
const char& get()
{
	return ref;
}

当函数返回指针或引用是要谨慎,虽然其实可能是const成员函数,但依然有可能修改内部成员变量。

参考文献

《C++ primer》 5th 中文版
《Effective C++》第三版

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值