重载索引运算符以模仿 POD 多维数组?
Overload index operator to mimic POD multi-dimensional array?
我有一个现有的 class,其结构如下:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
并随后以下列方式使用:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
我想用重载的索引运算符替换 Data
成员,这样我就可以对使用的索引执行范围检查。虽然我可以更改 Matrix
class 本身及其成员函数的实现,但我无法修改其在现有代码中的用法,因此任何解决方案都要求使用语法保持相同。还希望解决方案不改变 sizeof(Matrix)
。有办法实现吗?
一般来说,对于这种事情,您需要使用代理 class 来处理第二个索引运算符。它看起来像这样,然后进入 Matrix
class 的 private
部分。我将省略边界检查(您自己添加它应该不难)。
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[]
return 成为这个 class:
的一个实例
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
请注意,如果您想要一个 const 重载(即,您想要在 const Matrix
对象上使用索引运算符),您将需要一个单独的 ConstProxy class,它具有 const Matrix& ref
而不是 Matrix& ref
但在其他方面是相同的。
还有一个选项是 return引用一个数组。 (注意:正如其中一条评论所指出的,这对边界检查没有多大帮助,但我认为这很有趣,所以我将其保留在这里。)
float (&operator[](size_t i))[4] {
return Data[i];
}
它的语法非常神秘,我相信它在 Visual Studio 2013 中不起作用,但您可以使用 typedef 使其更清晰一些。
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
如果您不介意放弃方括号索引,还有一种选择。您可以像这样重载函数调用运算符:
float operator()(size_t i, size_t j) {
return Data[i][j];
}
另一种方法是用向量
的语义定义代理class
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];
我有一个现有的 class,其结构如下:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
并随后以下列方式使用:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
我想用重载的索引运算符替换 Data
成员,这样我就可以对使用的索引执行范围检查。虽然我可以更改 Matrix
class 本身及其成员函数的实现,但我无法修改其在现有代码中的用法,因此任何解决方案都要求使用语法保持相同。还希望解决方案不改变 sizeof(Matrix)
。有办法实现吗?
一般来说,对于这种事情,您需要使用代理 class 来处理第二个索引运算符。它看起来像这样,然后进入 Matrix
class 的 private
部分。我将省略边界检查(您自己添加它应该不难)。
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[]
return 成为这个 class:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
请注意,如果您想要一个 const 重载(即,您想要在 const Matrix
对象上使用索引运算符),您将需要一个单独的 ConstProxy class,它具有 const Matrix& ref
而不是 Matrix& ref
但在其他方面是相同的。
还有一个选项是 return引用一个数组。 (注意:正如其中一条评论所指出的,这对边界检查没有多大帮助,但我认为这很有趣,所以我将其保留在这里。)
float (&operator[](size_t i))[4] {
return Data[i];
}
它的语法非常神秘,我相信它在 Visual Studio 2013 中不起作用,但您可以使用 typedef 使其更清晰一些。
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
如果您不介意放弃方括号索引,还有一种选择。您可以像这样重载函数调用运算符:
float operator()(size_t i, size_t j) {
return Data[i][j];
}
另一种方法是用向量
的语义定义代理class 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];