多维数组:运算符重载

Multidimensional array: operator overloading

本文关键字:运算符 重载 数组      更新时间:2023-10-16

我有一个带有多维数组的类:

  • 可以创建一、二、。。。,具有此类的n维阵列

  • 如果数组有n个维度,我想使用n个operator[]来获得一个对象:

示例:

A a({2,2,2,2}]; 
a[0][1][1][0] = 5;

但数组不是指向其他向量等的指针的向量。

所以我希望操作符[]返回一个类对象,直到最后一个维度,然后返回一个整数

这是一个非常简化的代码,但它显示了我的问题:

我收到的错误:"[Error] cannot convert 'A::B' to 'int' in initialization"

#include <cstddef>     // nullptr_t, ptrdiff_t, size_t
#include <iostream>    // cin, cout...
class A {
    private:
        static int* a;
    public:
        static int dimensions;
        A(int i=0) { 
            dimensions = i;
            a = new int[5];
            for(int j=0; j<5; j++) a[j]=j; 
        };
        class B{
            public:
                B operator[](std::ptrdiff_t);
        };
        class C: public B{
            public:
                int& operator[](std::ptrdiff_t);
        };
        B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
    B res;
  if (dimensions <= 1){
    res = C();
}
  else{
    res = B();
  }
  dimensions--;
  return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
    B res;
    if (dimensions <=1){
        res = B();
    }
    else{
        res = C();
    }
    dimensions--;
    return res;
}
int& A::C::operator[](std::ptrdiff_t i){
    return *(a+i);
}

int main(){
    A* obj = new A(5);
    int res = obj[1][1][1][1][1];
    std::cout<< res << std::endl;
}

operator[]obj[1][1]...[1]中从左到右求值,因此obj[1]返回一个B对象。假设现在您只有int res = obj[1],那么您将为B对象(或者在多次调用[]的情况下为C对象)分配int,但没有从BCint的转换。您可能需要编写一个转换运算符,如

operator int()
{
   // convert to int here
}

对于ABC,因为重载运算符不被继承。

我只是通过为AB编写这样的运算符就消除了您的编译错误(当然,我也有链接错误,因为有未定义的函数)。

此外,请注意,如果要编写类似obj[1][1]...[1] = 10的内容,则需要重载operator=,因为从intA或代理对象没有隐式转换。

希望这是有道理的。

附言:另请参阅@Oncaphillis的评论!

vsoftco是完全正确的,如果您想实际访问元素,则需要实现重载运算符。如果你想让它是动态的,这是必要的,这就是你描述它的方式。我实际上认为这是一个有趣的问题,所以我实现了你描述的模板。我认为它是有效的,但有些地方可能有点偏离

template<typename T>
class nDimArray {
    using thisT = nDimArray<T>;
    T                    m_value;
    std::vector<thisT*>  m_children;
public:
    nDimArray(std::vector<T> sizes) {
        assert(sizes.size() != 0);
        int thisSize = sizes[sizes.size() - 1];
        sizes.pop_back();
        m_children.resize(thisSize);
        if(sizes.size() == 0) {
            //initialize elements
            for(auto &c : m_children) {
                c = new nDimArray(T(0));
            }
        } else {
            //initialize children
            for(auto &c : m_children) {
                c = new nDimArray(sizes);
            }
        }
    }
    ~nDimArray() {
        for(auto &c : m_children) {
            delete c;
        }
    }
    nDimArray<T> &operator[](const unsigned int index) {
        assert(!isElement());
        assert(index < m_children.size());
        return *m_children[index];
    }
    //icky dynamic cast operators
    operator T() {
        assert(isElement());
        return m_value;
    }
    T &operator=(T value) {
        assert(isElement());
        m_value = value;
        return m_value;
    }
private:
    nDimArray(T value) {
        m_value = value;
    }
    bool isElement() const {
        return m_children.size() == 0;
    }
    //no implementation yet
    nDimArray(const nDimArray&);
    nDimArray&operator=(const nDimArray&);
};

基本思想是,这个类既可以充当数组的数组,也可以充当元素。这意味着事实上,数组的数组可以是元素的数组!当您想要获取一个值时,它会尝试将其强制转换为一个元素,如果不起作用,它只会抛出一个断言错误。

希望这是有意义的,当然,如果你有任何问题,请走开!事实上,我希望你能问,因为你描述的问题的范围比你想象的要大。

使用俄罗斯娃娃风格的模板类可能会很有趣。

// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
    foo<d-1, n> data[n];
public:
    foo<d-1, n>& operator[](std::ptrdiff_t x)
    {
        return data[x];
    }
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
    int data[n];
public:
    int& operator[](std::ptrdiff_t x)
    {
        return data[x];
    }
};
int main(int argc, char** argv)
{
    foo<3, 10> myFoo;
    for(int i=0; i<10; ++i)
        for(int j=0; j<10; ++j)
            for(int k=0; k<10; ++k)
                myFoo[i][j][k] = i*10000 + j*100 + k;
    return myFoo[9][9][9]; // would be 090909 in this case
}

每个维度都保留一个以前维度元素的数组。维度1使用跟踪1D int数组的基本专门化。维度2将保持一维数组的数组,D3将具有二维数组的数组等。然后访问看起来与本地多维数组相同。在我的例子中,我在类中使用数组。这使得n维数组的所有内存都是连续的,并且不需要在类内部进行动态分配。但是,您也可以通过动态分配提供相同的功能。