回 帖 发 新 帖 刷新版面

主题:[原创]理解C++ — 变量与常量(1)

变量与常量(1)

程序运行时,所用的数据首先要被放在内存。内存有两个最基本的属性,一个是它的地址(编号),另一个就是它存储的数据。就如一堆小箱子,编号用来区分到底是用到哪个箱子,数值就如箱子里面放着的东西。

数据放在内存,我们给它一个名字,名字只不过是个符号,符号本身都是没有什么意义的,符号代表的东西才有意义。取了名字之后可以根据名字来方便取回我的数就行了。名字到最后都会影射到地址。可以说,名字是只是给人看的,那个人最可能是你自己,所以为了自己, 也为了别人幸福,请花点心思去取个好名字。

数据放在内存之后,可以分为变量与常量,常者,不变也;量者,数值也。前面已经说了,内存有地址和存储的数据两个最基本的属性,因此常量与变量当然也有两个最基本的属性了,一是它分配到的内存地址,另一个就是地址所指内存里面的数值。常量与变量就是从地址所标内存里面的数值可否变化来区分的。程序执行时数值可变为变量,不可变为常量。常量的数值在程序执行之前已经确定下来的了。当然变量与常量还有其它的要素,比如名字和类型。名字最终会影射到地址,类型可以决定它们的大小和行为。类型有其自身的意义。

从内存里面的数值是否可变可以区分变量与常量。那么从分配的内存地址来看呢,又可以将变量与常量分为 静态(static),动态(dynamic),自动(auto)三种不相同的状态。C++中,关键字const含义为不变(常), 关键字static含义为固定(静)。照我理解(注意,是我自己的理解),常和静,变和动,都是一个意思,指变化和不变化,只不过常和变是对于内存存储的数而言,静和动是对于内存地址而言。

好啦。现在看看静态,动态,和自动到底是什么含义,怎么去区分? 当程序刚启动,系统会分配些栈啊,程序控制块啊,各个段啊之类,这可以算一个准备阶段,在这个准备阶段,程序代码还没有正式执行,常量与常量所需的内存已经分配好了,地址已经确定下来,这就为静态。当程序代码已经执行,才去分配内存,内存地址还没有确定,为动态或者自动。要是代码正在执行,需要内存分配,这一个分配行为由系统全部完成,不用你去操心,就为自动;要是需要程序员自己决定分配的时机,显式调用malloc,new 之类的分配函数,就为动态。概括的说,程序执行之前已经分配好内存,决定好内存地址,为静态; 程序执行之时再分配,分两种情况,1)系统自动完成,为自动类型。2)需要显式调用分配函数,自己决定时机,为动态。

将属性关联到数据的过程,叫做绑定(binding)。如果在程序执行之前,变量与常量的属性已经确定了,就叫静态绑定;要是要等到程序执行之时,属性才被关联,被确定,就叫动态绑定。看看C++的书籍,静态,动态,绑定的概念会老是出现的, 到这里应该有大概的理解了,主要是以属性确立的时机来区分。其实不单是变量,常量,有时候调用什么函数(也就是函数的地址)也需要在程序执行之时才能确定。这时候可以先将函数地址先存起来,或者做成一个表。可能有人问,怎么函数地址也可以放起来的吗? 当然了,函数也需要内存来放,既然放在内存,为了找回它,就一定要得回它的位置,也就地址。对于计算机来说,所有东西都是101010之类的数值,什么都已经没有区别了。既然如此,函数,代码,浮点,对象,跟int之类的整型没有什么两样。int可以先放着,函数为什么不可以?

===================================================================
C++中,const是个很重要的关键字,施加了一种约束。有约束其实不是件坏事情,无穷的权利意味着无穷的灾难。应用了const之后,就不可以改变变量的数值了,要是一不小心改变了编译器就会报错,你就容易找到错误的地方。不要害怕编译器报错,正如不要害怕朋友指出你的缺点,编译器是写程序人的朋友,编译时期找到的错误越多,隐藏着的错误就会越少。所以,只要你觉得有不变的地方,就用const修饰,用得越多越好。比如你想求圆的周长,需要用到Pi, Pi不会变的,就加const,const double Pi = 3.1415926; 比如你需要在函数中传引用,只读,不会变的,前面加const; 比如函数有个返回值,返回值是个引用,只读,不会变的,前面加const; 比如类中有个private数据,外界要以函数方式读取,不会变的,加const, 这个时候就是加在函数定义末尾,加在末尾只不过是个语法问题。其实语法问题不用太过注重,语法只不过是末节,记不住了,翻翻书就可以了,接触多了,自然记得,主要是一些概念难以理解。你想想,const加在前面修饰函数返回值,这时候const不放在末尾就没有什么地方放了。

不过const修饰指针就需要注意一下了。要是修饰的类型不是指针,比如int之类,const放在int之前和int之后是一样的,比如
const int a = 2;
int const a = 2;
有着同样的效果。我自己偏向于第一种写法,其实想想,第二种写法更为合理,表示修饰变量a本身,所以a的值不可变。
当类型为指针时,以星号*为界, const加在左右两边,有不同的意思。
1) const int* pa = &a; (可以写成 int const* pa = &a; 注意是以星号为界)
2) int* const pa = &a;
写法1)表示pa所指向的变量,也就是a的值不可变。写法2)表示pa的指向,也就是pa本身的值不可以变,不可以现在指向a, 跟着指向b.
=======================================
int a = 2;
int b = 3;
const int* pt = &a;
//*pa = 1;            Error
pa = &b;              OK  

===================================== 
int a = 2;
int b = 3;
int* const pt = &a;
*pa = 1;             OK
//pa = &b;           Error   

==================================
前面已经说过了,const用来指示内存中的数值不会变。指针本质上是一个地址(编号), 这个编号也需要放在内存。所以pa这个变量放在内存,数值是一个地址。当const在*右边,const直接修饰pa, 表示pa的数值不会变,所以也就不可以改变指向。当const在*左边,就修饰指向的变量,故*pa的值不能变。要是const int* const pa = &a; a的值不可变,pa的指向也不可变。请仔细想一想。这个问题困惑了我很久的了。

(注: 以上是个人观点,有理无理,回帖评论)
                                                              

回复列表 (共34个回复)

21 楼

UP

22 楼

总结的好!赞!其实发现往往真正到达一定水平才能将一些貌似简单的问题解释的很清楚!

23 楼


顶!

24 楼

楼主真强大 啊,个人觉得写得相当好啊!!!对变量与常量已经写得相当的清楚了啊,const也把大概思想表达出来了,看来楼主对C++的理解绝非一般啊。真的很希望您继续写下去,我一定会全力支持的!!!非常谢谢提供这么好的东西!!!

25 楼

support !!!!请继续。。。。

26 楼

其实学c++
你教的再多,还不如他自己花半个小时自己练习一下
当然,自己练习然后再看高手的建言更好了

27 楼

很好,受益颇多!!![code=c]
请填写代码
[/code]

28 楼

我觉得把const放在类型后面更好理解,比如说 int *const P ,const的前面是什么,就是把什么申明为不变,比如const在*后,就说明指针不变;int const *p ,const在int后就声明 int为不变。。

29 楼

个人感觉楼主写的不错,但是最好把const这部分轻描淡写就行了,个人认为const部分就是个绕口令,能用明白就行,如果想三言两语就说清楚,呵呵,还真做不到!

30 楼

good

我来回复

您尚未登录,请登录后再回复。点此登录或注册