C++ C++;访问二维数组中的元素的步骤

C++ C++;访问二维数组中的元素的步骤,c++,arrays,multidimensional-array,operator-overloading,C++,Arrays,Multidimensional Array,Operator Overloading,我正在寻找二维数组指针的重载[]运算符 访问单元格元素 二维数组作为int*arr传递给我的函数 我们可以通过*(arr+i*N+j)访问cell元素,其中N是列计数 i是行索引,j是列索引 但是我们可以像arr[i,j]或arr(i,j)那样编写它以提高可读性吗 使用一些宏或运算符重载 有什么建议吗?无法更改内置类型运算符的行为。如果要重载运算符,至少一个操作数必须是用户定义的类型。否 运算符重载要求至少一种参数类型为类/结构/联合。宏不能做到这一点 如果可能的话,最接近的方法是通过引用传递数

我正在寻找二维数组指针的重载[]运算符 访问单元格元素

二维数组作为
int*arr
传递给我的函数

我们可以通过
*(arr+i*N+j)
访问cell元素,其中
N
是列计数
i
是行索引,
j
是列索引

但是我们可以像
arr[i,j]
arr(i,j)
那样编写它以提高可读性吗 使用一些宏或运算符重载


有什么建议吗?

无法更改内置类型运算符的行为。如果要重载运算符,至少一个操作数必须是用户定义的类型。

运算符重载要求至少一种参数类型为类/结构/联合。宏不能做到这一点

如果可能的话,最接近的方法是通过引用传递数组。例如:

template<std::size_t width, std::size_t height>
void doThings(int(& array)[width][height])
{
    // access array[i][j];
}
或者你需要在这里解决潜在的问题。为什么一个2D数组首先要经过
int*

这里要记住的重要一点是不要使事情过于复杂。

  • 您可以编写一个索引函数来隐藏公式

    如果您的
    N
    是全局定义的,请编写

    int index(int i, int j) {
        return i * N + j;
    }
    
    和它一起使用

    arr[index(i, j)]
    
  • 或者,围绕指针编写一个包装器类。这个类的编写完全没有运行时开销。它可以有一个运算符来允许语法

    arr[i][j]
    
    其中,
    arr
    是包装类的一个实例。这样的包装可以这样定义:

    class Array2DWrapper {
        int *ptr;
    public:
        Array2DWrapper(int *ptr) : ptr(ptr) {}
    
        int * operator[](int i) {
            return ptr + i*N;
        }
    };
    
    // USAGE:
    void exampleFunction(int *arrPtr) {
        Array2DWrapper arr { arrPtr };
        ...
        arr[i][j];
        ...
    }
    
    如您所见,其思想是为外部维度重载
    操作符[]
    ,从而返回指向内部维度的指针。当这个类的用户写入
    arr[i]
    时,它调用自定义操作符重载,它返回一个
    int*
    ,然后下一个
    [j]
    使用内置的
    操作符[]
    作为指针访问元素

    请注意,上面的类可以用作函数参数,但调用方可以使用指向某个2D数组的原始指针调用它。这将自动调用此类的构造函数(“隐式转换”)

    如果未全局定义
    N
    ,则应将其作为成员添加到类以及构造函数中

    class Array2DWrapperDynamicN {
        int *ptr;
        int N;
    public:
        Array2DWrapper(int *ptr, int N) : ptr(ptr), N(N) {}
    
        int * operator[](int i) {
            return ptr + i*N;
        }
    };
    
    但是现在,隐式转换不再起作用了

    // USAGE:
    void exampleFunction(int *arrPtr, int N) {
        Array2DWrapperDynamicN arr { arrPtr, N };
        ...
        arr[i][j];
        ...
    }
    

    • 你不能直接这么做。
      我建议编写一个小类/结构来方便地包装2D数组。这里我使用
      std::vector
      而不是
      int*arr
      ,您不必关心内存管理。以下代码显示了3种可能的方法:

      方法1(推荐):通过
      mat(i,j)
      操作符()(size\u ti,size\t j)
      被称为函数调用操作符

      template<typename T>
      struct Matrix
      {
          Matrix(const std::vector<T>& d, size_t s) : Matrix(d, s, s) {}
          Matrix(const std::vector<T>& d, size_t c, size_t r) : data_(d), cols_(c), rows_(r) {}
          std::vector<T> data_;
          size_t    cols_;
          size_t    rows_;
          const T& operator()(size_t i, size_t j) const { return data_[i * cols_ + j]; }
                T& operator()(size_t i, size_t j)       { return data_[i * cols_ + j]; }
          // and you can add other convenient methods
      };
      
      方法2:通过
      mat[{i,j}]
      使用数组下标操作符只需要一个参数,因此您可以更改/添加以下操作符到类中:

      const T& operator[](const std::array<size_t,2>& a) const { return data_[a[0] * cols_ + a[1]]; }
            T& operator[](const std::array<size_t,2>& a)       { return data_[a[0] * cols_ + a[1]]; }
      
      像这样使用它:

         Matrix<int> mat({1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 3); // a 3x3 matrix
         std::cout << mat(1,2) << std::endl;
      
      std::cout << mat[Idx(1),Idx(2)] << std::endl;
      

      std::难道我认为写arr[I,j]比写(arr+iN+j)更易读,后者更容易出错和不可读。建议你读第二个选项。“但是我们必须在课堂上的某个地方加上N?”维姬我把答案扩大了一点。我不知道在您的情况下,
      N
      是全局定义的,还是需要放在包装器中。这取决于代码的其余部分。。。
      N
      来自哪里?它是一个函数参数吗?还是函数之外?你的隐式转换非常好。但如果N可以参与隐式转换,那就太好了,因为N不是全局定义的。如果能看到普通指针转换成具有2d索引功能的智能指针,那就太好了。@vicky但要做到这一点,它需要以某种方式知道内部尺寸的大小。。。在C++11中,可以使用初始值设定项列表对多个参数构造函数进行隐式转换。这有点复杂。基本上,您可以这样调用函数:
      exampleFunction({arr,N})
      ,请参见
      {arr,N}
      exampleFunction
      的单个参数,如果函数具有签名
      exampleFunction(array2drapperdynamicn-arr),则会隐式转换为
      array2drapperdynamicn
      通常情况下,行和列计数作为参数列表在2D数组后面传递,如exampleFunction(arr,m,n)。。。。在这种情况下我们能做些什么吗?这是什么类型的操作员?(我猜你希望第二个是非常量)这是操作符:
      mat(I,j)
      。是的,很抱歉,当你编写代码时没有测试它;p:)关于带有两个参数的数组下标运算符:这确实只有在重载逗号运算符时才可能,但对于内置类型的两个参数,这同样是不可能的。通常的“变通方法”是使用语法
      [i][j]
      (如我的回答中所示)。它还以更好的方式类似于原始二维数组的经典语法。但这当然是一种主观偏好。哦,对了,谢谢你的观点,逗号运算符重载也是不可能的。我会更仔细地看看你的答案!
      template<typename T, size_t Cols, size_t Rows> struct Matrix 
      { 
        std::array<T, Cols * Rows> data_; 
        // etc...
      
      const T& operator[](const std::array<size_t,2>& a) const { return data_[a[0] * cols_ + a[1]]; }
            T& operator[](const std::array<size_t,2>& a)       { return data_[a[0] * cols_ + a[1]]; }
      
      struct Idx 
      {
          Idx(size_t ii) : i(ii) {}
          size_t i;
          operator size_t() const { return i; } // implicit user-defined conversion
      };
      
      std::array<size_t, 2> operator , (Idx i1, Idx i2)
      {
          return { i1, i2 };
      }
      
      // etc...
      // and we do not have to add Matrix operators since we reused the one from Method 2
      
      std::cout << mat[Idx(1),Idx(2)] << std::endl;