通过对 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 编译了这段代码并编译了它。我有两个问题。
- 在
Vec
复制构造函数中,我们将一个常量引用传递给Vec v
。通过 v
的常量扩展,v.vec
也应该是 const std::vector<int>&
。那么它是如何被复制到类型 std::vector<int>
?
- 如果 class 的常量性不适用于其成员变量,则上述情况唯一合乎逻辑的方式。所以我的问题是 class 的常量性对其成员变量有什么影响?
class 的常量适用于其成员变量,但不适用于作为引用的成员变量的引用对象。这类似于指针成员,其中指针是 const,但不是它指向的内容。
- 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 ?
- 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 继承的原因。
我对 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 编译了这段代码并编译了它。我有两个问题。
- 在
Vec
复制构造函数中,我们将一个常量引用传递给Vec v
。通过v
的常量扩展,v.vec
也应该是const std::vector<int>&
。那么它是如何被复制到类型std::vector<int>
? - 如果 class 的常量性不适用于其成员变量,则上述情况唯一合乎逻辑的方式。所以我的问题是 class 的常量性对其成员变量有什么影响?
class 的常量适用于其成员变量,但不适用于作为引用的成员变量的引用对象。这类似于指针成员,其中指针是 const,但不是它指向的内容。
- 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 ?
- 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 继承的原因。