通过对 class 的 const 引用复制成员变量

Copying member variable through const reference to a class

我对 class 的 const 引用的理解是我们不能修改 class 的状态,即不能执行任何修改它的任何成员变量的操作。但是请考虑以下代码。

#include <iostream>
#include <vector>

struct Vec {
  Vec(std::vector<int>& v) : vec(v) {}
  Vec(const Vec& v) : vec(v.vec) {
    v.vec.resize(100);
  }

  std::vector<int>& vec;
};

int main() {
  std::vector<int> x;
  Vec v1(x);
  Vec v2(v1);
  v1.vec.resize(10, 0);
  v2.vec[5] = 8;
  std::cout << v1.vec[5] << std::endl;
  return 0;
}

我使用带有 -Wall 标志的 g++:4.8.3 编译了这段代码并编译了它。我有两个问题。

  1. Vec复制构造函数中,我们将一个常量引用传递给Vec v。通过 v 的常量扩展,v.vec 也应该是 const std::vector<int>&。那么它是如何被复制到类型 std::vector<int> ?
  2. 如果 class 的常量性不适用于其成员变量,则上述情况唯一合乎逻辑的方式。所以我的问题是 class 的常量性对其成员变量有什么影响?

class 的常量适用于其成员变量,但不适用于作为引用的成员变量的引用对象。这类似于指针成员,其中指针是 const,但不是它指向的内容。

  1. In Vec copy construtor, we pass a const reference to a Vec v. By extension of constness of v, v.vec should also have been a const std::vector&. Then how does it get copied to type std::vector ?
  2. The only logical way the above can happen is if constness of a class doesn't apply to it's member variable. So my question is what implications does a constness of a class has on it's member variables ?

const 并不是这样扩展的。您将 const 粘贴在类型的 back 上,而不是前面。考虑以下代码...

struct foo {
    foo() {}

    int * i;
};

int main (void)
{
    foo my_foo;

    int * &a = my_foo.i;
    const int * &b = my_foo.i;
    int * const &c = my_foo.i;

    const foo const_foo;

    int * &d = const_foo.i;
    const int * &e = const_foo.i;
    int * const &f = const_foo.i;

    return 0;
}

foo.cpp: In function ‘int main()’:
foo.cpp:12: error: invalid initialization of reference of type ‘const int*&’ from expression of type ‘int*’
foo.cpp:16: error: invalid initialization of reference of type ‘int*&’ from expression of type ‘int* const’
foo.cpp:17: error: invalid initialization of reference of type ‘const int*&’ from expression of type ‘int* const’

这表明 const_foo.i 的类型为 int * const,与 const int * 不同。类型 int * const 不保证其指向的数据不会改变,只是指针本身不能改变。

在您的示例中,v2.vec 的类型为 std::vector<int> & const。但是那个类型是没有意义的(也是非法的),因为无论如何你都不能改变引用的别名。为此,std::vector<int> 已经是 const。


常量性继承是可能的,但您必须明确编写该规则。以下代码将愉快地拒绝编译,因为通过限制调用者使用 getter 来强制执行 const 限制,从而使您正在寻找的合同...

#include <iostream>
#include <vector>

struct Vec {
    Vec(std::vector<int>& v) : _vec(v) {}
    Vec(const Vec& v) : _vec(v.vec()) {
        v.vec().resize(100);
    }

    // How to make const-ness inherit...
    std::vector<int> & vec() { return _vec; }
    std::vector<int> const & vec() const { return _vec; }

    private:
    std::vector<int>& _vec;
};

int main() {
    std::vector<int> x;
    Vec v1(x);
    Vec v2(v1);
    v1.vec().resize(10, 0);
    v2.vec()[5] = 8;
    std::cout << v1.vec()[5] << std::endl;
    return 0;
}

一旦你开始这样做,你就会进入一个奇怪的领域,因为它允许我调用 std::vector<int> const & vec() const,保存对 _vec 的 'data-const' 引用,然后让其他代码更改 vec 中的数据,违反了早期代码的 const 契约。那里有很多地雷,这可能就是为什么该语言没有内置这种 const 继承的原因。