4

让我们看看下面的 C++ 代码:

#include <iostream>

int main()
{
    int z = 2;

    class A {
        public:
        const int & x;
        A(const int & x) : x(x) {}
        void show(){
            std::cout << "x=" << this->x << std::endl ;
        }
    } a(z);

    a.show();
    z = 3;
    a.show();
}

程序打印:2和3

它清楚地表明,虽然不能修改 A x 类内部,但这仅意味着它是只读的,因为我可以从外部更改它的值。

当然,我可以将它作为存储在 A 类中的副本,但我想知道是否有(或者是否有提议?)对 A 类说成员 x 将是真正的常量,而不仅仅是读取只是,承诺外部代码不会改变它的意思吗?

在我看来,它看起来与 C限制关键字的含义有关,但我还没有听说过任何这样的 C++ 功能。你 ?

4

4 回答 4

4

常量是实际变量的一个属性。

该术语const int& x仅表示“x 是对不会修改的 int 的引用”,当然编译器会强制执行此操作。

如果您希望 x 引用的实际变量为 const,只需将其声明为:

#include <iostream>

int main()
{
    const int z = 2;    // declared const. Nothing may ever modify it

    class A {
    public:
        const int & x;
        A(const int & x) : x(x) {}
        void show(){
            std::cout << "x=" << this->x << std::endl ;
        }
    } a(z);

    a.show();
    z = 3;        // this is a logic error, caught by the compiler.
    a.show();
}

正确编译会产生错误:

./const.cpp:41:7: error: read-only variable is not assignable
    z = 3;
    ~ ^
1 error generated.
于 2015-12-29T11:48:29.683 回答
3

您正在寻找 D 的immutable关键字,它作为该语言中的一个新概念被引入,正是因为不幸的是,答案是否定的:它在 C++ 中不存在。

于 2015-12-29T11:03:36.077 回答
2

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_castconst_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_castreinterpret_cast

于 2015-12-29T11:39:41.790 回答
0

我认为这是程序员的设计问题,而不是语言。变量意味着该const变量的任何用户,他们不应该更改该变量的值。我们的编译器足够聪明,可以帮助我们确保这一点。A用户也是如此z,如果您想A知道A::x对变量的引用const,那么您应该创建z一个const int. 这const reference只是为了保持用户和提供者之间的合同。

于 2015-12-29T12:34:38.183 回答