我有一个现有的类,其结构如下:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
随后以下列方式使用:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
我想用重载的索引操作符替换Data
成员,因此我可以对使用的索引执行范围检查。虽然我可以更改Matrix
类本身及其成员函数的实现,但我无法在现有代码中修改其用法,因此任何解决方案都要求使用语法保持相同。解决方案也不会改变sizeof(Matrix)
。有没有办法实现这个目标?
答案 0 :(得分:3)
通常,对于这种情况,您需要使用代理类来处理第二个索引运算符。它看起来像这样,然后进入private
课程的Matrix
部分。我会忽略边界检查(你不应该自己添加它)。
class Proxy {
Matrix& ref;
size_t i;
public:
Proxy(Matrix& on, size_t i) : ref(on), i(i) {}
float operator[] (size_t j) {
return ref.Data[i][j];
}
};
然后让你的Matrix::operator[]
返回此类的一个实例:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
注意,如果你想要一个const重载(即你想在const Matrix
个对象上使用索引操作符),你需要一个单独的ConstProxy类,它有const Matrix& ref
而不是{ {1}}但在其他方面是相同的。
还可以选择返回对数组的引用。 (注意:正如其中一条评论指出的那样,这对边界检查没什么帮助,但我觉得它很有意思,所以我将它留在这里。)
Matrix& ref
该语法相当神秘,我相信它在Visual Studio 2013中不起作用,但你可以使用typedef使其更清晰。
float (&operator[](size_t i))[4] {
return Data[i];
}
如果您不介意放弃方括号索引,还有一个选择。您可以像这样重载函数调用操作符:
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
答案 1 :(得分:1)
另一种方法是使用向量的语义定义代理类
class Matrix
{
public:
struct SubMatrix
{
class Vector
{
public:
Vector(float *data) : Data(data) {}
float &operator[](int index) { return Data[index]; }
private:
float *Data;
};
Vector operator[](int index)
{
return Vector(Data[index]);
}
float Data[4][4];
};
SubMatrix Data;
// ... methods
};
然后你可以这样使用它:
Matrix m;
float f = m.Data[1][2];