const
并不意味着“这个值只能在特殊情况下改变”。相反, const 的意思是“你不能用它做任何事情都会导致它以任何方式改变(你可以观察到)”
如果您有一个 const 限定变量,则编译器的命令(以及您自己选择首先限定它的)不允许您const
做任何会导致它改变的事情。就是const
这样。尽管您采取了行动,但它可能会改变,如果它是对非 const 对象的 const 引用,或者出于任何其他原因。如果您作为程序员知道所指对象实际上不是恒定的,则可以将其丢弃const_cast
并更改。
但在你的情况下,一个常量成员变量,这是不可能的。const 限定变量不能是对非 const 的 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 已初始化的值上分配了一个零。
但是对 const 限定词的修改不会导致可观察到的变化。因此,GCC 产生了一个相当长的链,将 42 放入 %0,然后将 42 放入 %1,然后将其再次存储到 %retval,然后将其加载到 %retval2。因此,G++ 将让这段代码满足这两个要求,const 被丢弃,但没有可观察到的变化i
,main 返回 42。
如果您需要一个可以更改的值,例如在标准容器的元素中,那么您不需要const
.
考虑使用private:
具有公共 getter 和私有 setter 方法的成员。