const
并不意味着“只有在特殊情况下才能更改此值”。相反,
const
的意思是“您所允许使用它的任何操作都不会导致它以任何方式发生更改(您可以观察到)”。
如果您有一个带有
const
限定符的变量,则根据编译器的规定(以及您首先选择用
const
进行限定的选择),您不允许执行任何会导致其更改的操作。这就是
const
的作用。如果它是对非常量对象的const引用或任何其他原因的const引用,则可能会在您的操作下发生更改。如果作为程序员,您“知道”引用实际上并不是常量,则可以使用
const_cast
将其转换并进行更改。
但是,在您的情况下,作为常量成员变量,这是不可能的。该
const
限定符的变量不能是非常量的常量引用,因为它根本不是引用。
编辑:为了激动人心地说明这一切及为什么应该遵守const正确性,请看一下真正的编译器实际上做了什么。考虑这个简短的程序:
int main() {
const int i = 42;
const_cast<int&>(i) = 0;
return i;
}
以下是LLVM-G++的输出:
; ModuleID = '/tmp/webcompile/_2418_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-linux-gnu"
define i32 @main() nounwind {
entry:
%retval = alloca i32 ; <i32*> [#uses=2]
%0 = alloca i32 ; <i32*> [#uses=2]
%i = alloca i32 ; <i32*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i32 42, i32* %i, align 4
store i32 0, i32* %i, align 4
store i32 42, i32* %0, align 4
%1 = load i32* %0, align 4 ; <i32> [#uses=1]
store i32 %1, i32* %retval, align 4
br label %return
return: ; preds = %entry
%retval2 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval2
}
特别值得注意的是代码行
store i32 0, i32* %i, align 4
。这表明
const_cast
是成功的,我们实际上将一个零分配到了已初始化的
i的值上。
但是,对于常量限定符的修改不会导致可观察的变化。因此,GCC会产生一个相当长的链,将42放入%0中,然后将其加载到%1中,再将其存储到%retval中,然后将其加载到%retval2中。因此,G++将使此代码同时满足两个要求:const被强制转换,但
i没有发生可观察的变化,main函数返回42。
如果需要一个可以更改的值,例如在标准容器的元素中,则不需要使用
const
。考虑使用具有公共getter和私有setter方法的
private:
成员。