是否重载索引运算符以模拟POD多维数组

Overload index operator to mimic POD multi-dimensional array?

本文关键字:POD 数组 模拟 重载 索引 运算符 是否      更新时间:2023-10-16

我有一个现有的类,它的结构如下:

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)。有办法做到这一点吗?

对于这类事情,通常需要使用代理类来处理第二个索引运算符。它看起来像这样,并进入Matrix类的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[]返回这个类的一个实例:

Proxy operator[] (size_t i) {
    return Proxy(*this, i);
}

请注意,如果您想要一个const重载(即,您想要在const Matrix对象上使用索引运算符(,则需要一个单独的ConstProxy类,该类具有const Matrix& ref而不是Matrix& ref,但在其他方面是相同的。


还可以选择返回对数组的引用。(注意:正如其中一条评论所指出的,这对绑定检查没有多大帮助,但我认为这很有趣,所以我将把它留在这里。(

float (&operator[](size_t i))[4] {
    return Data[i];
}

它的语法非常晦涩,我相信它在VisualStudio2013中不起作用,但你可以用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 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];