重载索引运算符以模仿 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];