Int& 到 const int -static 与 dynamic-
Int& to const int -static vs dynamic-
class A
{
public:
A(int i = 25) {x = i;y=new int[i];for(int j=0;j<i;j++) y[j]=j;}
int& f() const {return x;}
int& operator[](int i) const {return y[i];}
private:
int x,*y;
};
int main()
{
A a(15);
cout << a[5];
cout << a.f();
return 0;
}
当我试图编译它说的代码时
"Invalid initialization of reference of type int& from expression of type const int"
关于 f() 函数。
我明白了,因为它 returns 对函数声明为 const 的东西的非常量引用。但它不应该与 [] 重载的行为相同吗?
它还 returns 对函数声明为 const 的东西的非 const 引用,但它在那里没有显示错误。
有什么区别?
问题在这里:
int& f() const {return x;}
您的函数被标记为 const
,因此它只能被 const
个实例调用。但是,您 return 是一个非 const
引用,因此如果有效,您可以使用它来修改 const
实例。编译器对此不满意。因此 f()
应该 return const int&
代替。
另一方面,int& operator[](int) const
编译,因为你 return 对指针成员 y
指向的数据的引用,但你不能修改指针本身。换句话说,在 const
实例上,指针 y
是 const
,即 int * const y
,但不是数据。因此按位 const
-ness 被保留,但当然逻辑 const
-ness 不是,但是编译器只关心按位 const
-ness。
为了加强逻辑 const
的正确性,一种选择是编写两个版本的 operator[]
:
const int& operator[](int i) const {return y[i];}
和
int& operator[](int i) {return y[i];}
请注意,第二个版本应标记为非 const
,否则您将尝试重载两个仅在 return 类型上不同的函数。如果你想避免非const
版本中的代码重复,你可以通过const_cast
使用const
版本,比如
int& operator[](int i)
{
return const_cast<int&>(const_cast<const A&>(*this)[i]); // use the const version
}
编辑
有人提议为类似指针的数据成员引入 const
传播包装器 propagate_const
,这实际上也会使数据指向 const
,请参见
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4057.pdf
它告诉您不能 return 从 const
成员函数中对数据成员的非 const 左值引用。你需要
const int& f() const {return x;}
如果需要,您可以决定提供非常量重载:
int& f() {return x;}
至于operator[]
,它没有return对数据成员的引用。您不能通过 operator[]
修改 x
或 y
,因此它实际上是一个 const
成员函数。您可以决定禁止 y
对 指向 的数据进行修改,如果您的 class 为数组建模,这将是有意义的。但这不是绝对必要的,编译器没有理由强制执行它。
const int& operator[](int i) const {return y[i];}
int& operator[](int i) {return y[i];}
在 C++ 语言中,class 的常量意味着其所有成员的直接常量(mutable
成员除外)。但是,class 的常量性不会传播到指针成员 指向的数据 或引用成员 引用的。 pointed/referenced 数据不是 class 的一部分,它的常量不受 class.
常量的影响
在您的示例中,将成员函数声明为 const
使其将成员 x
和 y
视为 const
。但是,y
指向的数据并没有变成const
,例如*y
和 y[i]
都不是 const
.
从封闭的 class 到 pointed/referenced 数据的常量传播实际上是用户意图的一部分。根据您要实现的内容,您需要或不需要它。语言完全由您决定(或图书馆级解决方案)。
class A
{
public:
A(int i = 25) {x = i;y=new int[i];for(int j=0;j<i;j++) y[j]=j;}
int& f() const {return x;}
int& operator[](int i) const {return y[i];}
private:
int x,*y;
};
int main()
{
A a(15);
cout << a[5];
cout << a.f();
return 0;
}
当我试图编译它说的代码时
"Invalid initialization of reference of type int& from expression of type const int"
关于 f() 函数。
我明白了,因为它 returns 对函数声明为 const 的东西的非常量引用。但它不应该与 [] 重载的行为相同吗?
它还 returns 对函数声明为 const 的东西的非 const 引用,但它在那里没有显示错误。 有什么区别?
问题在这里:
int& f() const {return x;}
您的函数被标记为 const
,因此它只能被 const
个实例调用。但是,您 return 是一个非 const
引用,因此如果有效,您可以使用它来修改 const
实例。编译器对此不满意。因此 f()
应该 return const int&
代替。
另一方面,int& operator[](int) const
编译,因为你 return 对指针成员 y
指向的数据的引用,但你不能修改指针本身。换句话说,在 const
实例上,指针 y
是 const
,即 int * const y
,但不是数据。因此按位 const
-ness 被保留,但当然逻辑 const
-ness 不是,但是编译器只关心按位 const
-ness。
为了加强逻辑 const
的正确性,一种选择是编写两个版本的 operator[]
:
const int& operator[](int i) const {return y[i];}
和
int& operator[](int i) {return y[i];}
请注意,第二个版本应标记为非 const
,否则您将尝试重载两个仅在 return 类型上不同的函数。如果你想避免非const
版本中的代码重复,你可以通过const_cast
使用const
版本,比如
int& operator[](int i)
{
return const_cast<int&>(const_cast<const A&>(*this)[i]); // use the const version
}
编辑
有人提议为类似指针的数据成员引入 const
传播包装器 propagate_const
,这实际上也会使数据指向 const
,请参见
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4057.pdf
它告诉您不能 return 从 const
成员函数中对数据成员的非 const 左值引用。你需要
const int& f() const {return x;}
如果需要,您可以决定提供非常量重载:
int& f() {return x;}
至于operator[]
,它没有return对数据成员的引用。您不能通过 operator[]
修改 x
或 y
,因此它实际上是一个 const
成员函数。您可以决定禁止 y
对 指向 的数据进行修改,如果您的 class 为数组建模,这将是有意义的。但这不是绝对必要的,编译器没有理由强制执行它。
const int& operator[](int i) const {return y[i];}
int& operator[](int i) {return y[i];}
在 C++ 语言中,class 的常量意味着其所有成员的直接常量(mutable
成员除外)。但是,class 的常量性不会传播到指针成员 指向的数据 或引用成员 引用的。 pointed/referenced 数据不是 class 的一部分,它的常量不受 class.
在您的示例中,将成员函数声明为 const
使其将成员 x
和 y
视为 const
。但是,y
指向的数据并没有变成const
,例如*y
和 y[i]
都不是 const
.
从封闭的 class 到 pointed/referenced 数据的常量传播实际上是用户意图的一部分。根据您要实现的内容,您需要或不需要它。语言完全由您决定(或图书馆级解决方案)。