说我有以下测试代码:
#include <iostream>
using namespace std;
class Vector3 {
public:
float data[3];
};
class Weird3 : public Vector3 {
public:
union {
struct { float &x, &y, &z; };
struct { float &r, &g, &b; };
};
Weird3() : x(Vector3::data[0]), y(Vector3::data[1]), z(Vector3::data[2]) {}
};
int main(int argc, char** argv) {
const Weird3 w;
w.x = 100; // Works ok!
cout << w.x << endl;
w.data[0] = 100; // Error: assignment of read-only location
cout << w.x << endl;
return 0;
}
为什么通过子类中的引用成员修改data
成员有效,但不能直接?另外,有没有更好的方法来实现这种行为?例如,我有一个模板类VectorN
,派生类Vector2
,Vector3
和Vector4
;我想使用data
,VectorN
,x
或y
,{{等子类中的成员修改z
中的r
成员1}},g
。
答案 0 :(得分:2)
为什么通过子类中的引用成员修改数据成员有效,但不能直接?
因为您没有修改参考。 C ++中的const
不是逻辑const
,它更像是按位const
。当你这样做时:
w.x = 100;
您实际上并未修改w.x
,因此允许这样做。 x
碰巧引用const
对象的不同数据成员的事实意味着这是未定义的行为。但它是完全合法的代码。你不应该这样做。
另外,有没有更好的方法来实现这种行为?
如果您希望能够修改const
对象上的成员,只需将它们设为mutable
即可。
答案 1 :(得分:1)
w
被声明为const
。 const
不适用于引用的成员(或指针时的指针)。
由于不允许使用float& const
,因此引用不太明确,因为您无法重新分配引用(因此默认情况下您可以将其视为& const
。)
但是指针更清楚易懂:
const float *x
这是一个指向常量float
的指针。您无法通过解除引用来为指定的值分配新值。
float* const y
这是指向float
的常量指针。您可以通过取消引用来为指针指定一个新值,但是您不能为指针指定一个新值(使其指向其他指针)。
现在声明const Weird3 w
使得所有字段在w(前一个示例的float* const
)中不可重新分配,但您可以修改它们的值。这意味着您实际上并未改变w
的状态,而是更改w
引用或指向的内容。
答案 2 :(得分:0)
为什么通过子类中的引用成员修改数据成员有效,但不是直接?
为什么它不直接工作很明显,你尝试修改const对象。为什么它允许你修改引用也很明显 - 你不是修改对象的状态,而是修改其他引用指向的其他内容。引用指向const对象本身或其他东西的事实在这里是不可见的(对于编译器)而且它不可能,它应该只阻止将const对象分配给左值引用。
所以问题是为什么你能够将const对象的成员分配给左值引用。答案是 - 对象的constness在构造函数中不可见。它可能会通过将来改变语言来改进,但现在就可以这样做了。
无论如何修改const对象会导致UB,所以你的评论&#34;工作正常&#34;是一种幻觉。
另外,有没有更好的方法来实现这种行为?
&#34;更好的&#34;方法是直接使用const_cast<>
。它至少是显式的,可以用来删除最初非const的对象的常量,但是通过修改得到它。再次,您不应该通过&#34; hack&#34;修改const对象。也不使用C cast或const_cast<>
,因为它会导致UB。