C++ const实现原理

const 用于修饰常量时,分两种情况


1. 被修饰的常量是基本类型

此时,程序在编译时,就将变量用常量来替换了。

	实现机制:这些在编译期间完成,对于内置类型,如int编译器可能使用常数直接替换掉对此变量的引用。而对于结构体不一定。
	看下面的例子:

const int j=100;    int *p=const_cast<int*>(&j);    *p=200;    cout<<j<<endl;   输出为什么是100呢?

cout<<*p<<endl; //输出是改过的200

编译器在优化代码时把cout<<j直接优化成cout<<100了,所以虽然p&j的值一样,但cout<<j不再通过访问j的地址输出。(反汇编时也有看到直接把数字压栈push 100 

这是因为,const型在压栈时,是使用的直接的数,就有点像C#define a 100

ps:

基本数据类型如下:

Name Description Size* Range*
char Character or small integer. 1byte signed: -128 to 127
unsigned: 0 to 255
short int (short) Short Integer. 2bytes signed: -32768 to 32767
unsigned: 0 to 65535
int Integer. 4bytes signed: -2147483648 to 2147483647
unsigned: 0 to 4294967295
long int (long) Long integer. 4bytes signed: -2147483648 to 2147483647
unsigned: 0 to 4294967295
bool Boolean value. It can take one of two values: true or false. 1byte true or false
float Floating point number. 4bytes +/- 3.4e +/- 38 (~7 digits)
double Double precision floating point number. 8bytes +/- 1.7e +/- 308 (~15 digits)
long double Long double precision floating point number. 8bytes +/- 1.7e +/- 308 (~15 digits)
wchar_t Wide character.or 4 bytes 1 wide character


2. const 变量修饰的是非基本类型。

此时,程序编译时,不知道该用什么值替换再编译;所以,将会用一块内存地址替换,然后再编译。

#include <iostream> 
using namespace std; 
struct A 
	{    
	int i;    
	char ch;    
	A()    
		{        
		i = 100;        
		ch = 'S';    
		} 
	}; 

int main() 
{    
	const A a;    
	const int i = 200;    
	int *p1 = (int*)&a.i;    
	int *p2 = (int*)&i;    
	*p1 = 1;    
	*p2 = 2; 
	//a.i = 200; //报错,左值不能为const    
	cout << a.i << " " << a.ch << endl;    
	cout << i << endl;    
	return 0; 
}

运行结果:

1 S 200


const用于修饰函数也包含两种情况

1. const在函数名前。

此种情况下表示,该函数返回值的类型使一个const类型。 

<span style="font-family: FangSong_GB2312;"><u>例如函数
</u></span><span style="font-family: FangSong_GB2312;"><span style="white-space: pre;">		</span>const char * GetString(void);
</span><span style="font-family: FangSong_GB2312;"><span style="white-space: pre;">	</span>如下语句将出现编译错误:</span><span style="font-family: FangSong_GB2312;">
<span style="white-space: pre;">		</span>char*str = GetString();
</span><span style="font-family: FangSong_GB2312;"><span style="white-space: pre;">	</span>正确的用法是</span><span style="font-family: FangSong_GB2312;">
<span style="white-space: pre;">		</span>const char *str =GetString();</span>


2. const在成员函数名之后

此种情况下表示,该函数中将不会对改类的成员变量做任何改变。

<span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);"><span style="white-space: pre;">	</span>任何不会修改数据成员的函数都应该声明为const</span><span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);">类型。</span><span style="font-family: FangSong_GB2312;">如果在编写</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数时,不慎修改了数据成员,或者调用了其它非</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数,编译器将指出错误,这无疑会提高程序的健壮性。以下程序中,类</span><span style="font-family: FangSong_GB2312;">stack</span><span style="font-family: FangSong_GB2312;">的成员函数</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">仅用于计数,从逻辑上讲</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">应当为</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">函数。编译器将指出</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">函数中的错误。</span><span style="font-family: FangSong_GB2312;">
classStack
{
<span style="white-space: pre;">	</span>public:
<span style="white-space: pre;">		</span>void Push(int elem);
<span style="white-space: pre;">		</span>int Pop(void);
<span style="white-space: pre;">		</span>int GetCount(void) const; // const </span><span style="font-family: FangSong_GB2312;">成员函数</span><span style="font-family: FangSong_GB2312;">
<span style="white-space: pre;">	</span>private:
<span style="white-space: pre;">		</span>intm_num;
<span style="white-space: pre;">		</span>int m_data[100];
};</span>
<span style="font-family: FangSong_GB2312;">
int Stack::GetCount(void)const
{
<span style="white-space: pre;">	</span>++ m_num; // </span><span style="font-family: FangSong_GB2312;">编译错误,企图修改数据成员</span><span style="font-family: FangSong_GB2312;">m_num
<span style="white-space: pre;">	</span>Pop();// </span><span style="font-family: FangSong_GB2312;">编译错误,企图调用非</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">函数</span><span style="font-family: FangSong_GB2312;">
<span style="white-space: pre;">	</span>return m_num;
}</span>
<span style="font-family: FangSong_GB2312;">
const </span><span style="font-family: FangSong_GB2312;">成员函数的声明看起来怪怪的:</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。</span><span style="font-family: FangSong_GB2312;">
</span><span style="font-family: FangSong_GB2312;">关于</span><span style="font-family: FangSong_GB2312;">Const</span><span style="font-family: FangSong_GB2312;">函数的几点规则:</span><span style="font-family: FangSong_GB2312;">

a.const</span><span style="font-family: FangSong_GB2312;">对象只能访问</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">而非</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">对象可以访问任意的成员函数</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">包括</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数</span><span style="font-family: FangSong_GB2312;">.
b.const</span><span style="font-family: FangSong_GB2312;">对象的成员是不可修改的</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">然而</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">对象通过指针维护的对象却是可以修改的</span><span style="font-family: FangSong_GB2312;">.
c.const</span><span style="font-family: FangSong_GB2312;">成员函数不可以修改对象的数据</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">不管对象是否具有</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">性质</span><span style="font-family: FangSong_GB2312;">.</span><span style="font-family: FangSong_GB2312;">它在编译时</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">以是否修改成员数据为依据</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">进行检查</span><span style="font-family: FangSong_GB2312;">.
e.</span><span style="font-family: FangSong_GB2312;">然而加上</span><span style="font-family: FangSong_GB2312;">mutable</span><span style="font-family: FangSong_GB2312;">修饰符的数据成员</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">对于任何情况下通过任何手段都可修改</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">自然此时的</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数是可以修改它的</span>

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值