关于常量

对于普通的变量

常量定义后不能被修改,所以在定义的时候必须被初始化。在这里有个问题需要思考,那么常量声明的时候需要加const修饰符吗?可以加吗?这个问题我们稍后自然明白了。

先看一个概念:const对象默认为文件的局部变量。即该变量只能在该文件中,不能被其他文件访问。

但是有个例外,如果const 对象被声明并定义为extern,则可以在整个程序中访问。

例如: extern const int sum = fcn();

在另外的文件中,通过声明: extern const int sum;则可以访问在定义文件处的变量。


总结:*非const变量其实是默认为extern,而要是const变量能够在其他的文件中访问,必须显示地指定为extern*

这句话包含了几个意思:第一个是extern关键字使得对象的作用域从文件作用域扩展为全局作用域。第二个,非const变量的默认作用域是全局,而const对象的默认作用域为文件作用域。第三个,要想使得const对象有全局作用域,必须加上extern关键字。

对于为什么const对象局部于文件创建,稍后可以讨论下。这个与头文件的设计有密切的关系。


这里我们先插入讲一下const引用,即指向const对象的引用。这是一个严格的规定。不能用一个普通的引用指向一个const对象。(思考下是不是这样呢?确实应该被规定吧?)

有更有趣的现象:

我们知道一个非const的引用不能指向一个字面常量。比如,int & a = 7.(想想都奇怪,难道说,a是7的别名吗?所以这是一个语法错误。)

但是,const引用能够被初始化为不同类型的对象(不管是不是常量),甚至被初始化为一个右值,比如一个字面常量。

比如: double a = 1.234;

         const int & b = a;

这是怎么一回事儿呢?其实是编译器的作用: 编译器会转化成下面的编码:

int temp = a;

const int & b = temp;

解释一下,这样编译带来的效果:

如果b 不是const的话,则可能可以通过修改b的值改变temp的值,但却并不改变a的值。这是引用的本意所不希望的。所以,非const的引用只能指向同类型的对象,以避免这种不期望的情况出现,而const引用则没有关系,你想啊,const本来就是只读的,我们并不会改变a的值啊!这在我们的期望之中。


现在我们回过头来讨论之前的问题,为什么const对象局部于文件创建?

这个与头文件的设计息息相关。

*头文件用于声明而不是用于定义*,这个应该好理解,头文件包含于多个文件中,如果用于定义,则结果一定是多处定义了。

但是这个规则有三个例外:类定义,值在编译时就已经知道的const对象和inline函数。

关于常量,我们只对const对象做一些解释.

为什么const对象默认为文件作用域,就是出于这方面的考虑,希望能够在头文件中被定义。这样行为的含义是:当我们在头文件中定义了const变量后,每个包含该头文件的源文件都有自己的const变量,其名称和值都相同。

为什么要这么做呢?这样根本不能多个文件共享同一个常量,还有什么用处呢?

问题出在了常量表达式上。

比如枚举成员的初始化必须是常量表达式,当然还有其他情况需要常量表达式。常量表达式要求在编译时就能计算出结果。为了让多个文件使用相同的常量值,const变量和它的初始化必须是每个文件都可见的,而要使初始化式可见,一般都把这样的const变量定义在头文件中,那样无论该const变量何时使用,编译器都能看见其初始化式。

如果,const变量不是用常量表达式初始化,那么它就不该在头文件中定义,而应该和其他变量一样,并使用extern关键字。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值