C++ 中的常量并不意味着不变性,而是所讨论的变量是只读的。它仍然可以被程序的其他部分修改。我理解您的问题,即是否可以在不知道调用者在做什么的情况下在被调用函数中强制执行真正的不变性。
当然,您可以创建一个完成任务的模板包装类:
template <typename T>
class Immutable
{
public:
template <typename ...Args>
Immutable( Args&&...args )
: x( std::forward<Args>(args)... )
{}
operator const T &() const
{
return x;
}
private:
const T x;
};
只要你不这样做,否则reinterpret_cast
当const_cast
你用Immutable<T>
.
但是,如果您对某个对象有一个常量引用,则无法判断程序的其他部分是否对该对象具有非常量访问权限。事实上,底层对象可能是一个全局或静态变量,您可以只读访问,但您调用的函数可能仍会修改它。
这不能发生在Immutable<T>
对象上。但是,使用Immutable<T>
可能会给您带来额外的复制操作。您需要判断自己是否可以忍受,以及成本是否值得收益。
拥有一个函数需要一个const Immutable<Something> &
而不是const Something &
作为参数会影响调用代码。可能会触发复制操作。或者,您可以要求Immutable<Something> &
不带const
. 然后不会触发意外复制,但调用代码必须传递对Immutable<Something>
对象的引用。这是正确的,因为如果调用者收到 aconst &
作为参数,那么调用者不知道该对象是否可能被程序中的其他人修改。调用者必须自己创建对象或要求将不可变对象作为引用传递给它。
你原来的问题
这是您的原始问题,Immutable<int> &
而不是const int &
.
#include <iostream>
int main()
{
Immutable<int> z = 2;
class A {
public:
const Immutable<int> & x;
A(Immutable<int> & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
//z = 3; // this would fail
a.show();
}
另一个例子
它是这样工作的:如果你写
void printAndIncrementAndPrint( int & i1, const int & i2 )
{
std::cout << i2 << std::endl;
++i1;
std::cout << i2 << std::endl;
}
int main()
{
int i = 0;
printAndIncrementAndPrint( i, i );
}
然后它将打印
0
1
进入控制台。如果您替换printAndIncrementAndPrint()
with的第二个参数const Immutable<int> & i2
并保持其余参数不变,则会触发副本并打印
0
0
到控制台。在不使用or破坏类型系统的情况下,您不能将 and 传递Immutable<int>
给函数和 a到相同的底层数据。int &
const_cast
reinterpret_cast