运算符重载 [][] 在C++中的2维数组

11

我有一个二维数组,我想定义一个函数,使用运算符重载来返回用户给我的索引值。

换句话说:

void MyMatrix::ReturnValue()
{
    int row = 0, col = 0;
    cout << "Return Value From the last Matrix" << endl;
    cout << "----------------------------------" << endl;
    cout << "Please Enter the index: [" << row << "][" << col << "] =" << ((*this).matrix)[row][col] << endl;
}
< p >操作< code >((*this).matrix)[row][col]应该返回一个< code >int。
我不知道如何构建operator [][]
或者,我可以将一些调用operator []串联起来,但我没有成功,因为对该运算符的第一次调用将返回int*,而第二次调用将返回int,这迫使我构建另一个运算符,我不想这样做。

数据矩阵的定义如下:


int** matrix; matrix = new int*[row];
if (matrix == NULL)
{
    cout << "Allocation memory - Failed";
}
for (int i = 0; i < row; i++)//Allocation memory
{
    matrix[i] = new int[col];
    if (matrix[i] == NULL)
    {
        cout << "Allocation memory - Failed";
        return;
    }
}

我能做些什么呢?谢谢。


2
简单来说,这样的运算符不存在,因此您无法对其进行重载。 - skypjack
1
好的,这意味着我必须为运算符[]构建两个函数,因为如果我这样做:(((*this).matrix)[row])[col],那么第一个运算符将返回int*,第二个将返回int。 - LIMA
@lilach 显示数据成员matrix的定义。 - Vlad from Moscow
int** matrix; matrix = new int*[row]; if (matrix == NULL) { cout << "Allocation memory - Failed"; } for (int i = 0; i < row; i++)//Allocation memory { matrix[i] = new int[col]; if (matrix[i] == NULL) { cout << "Allocation memory - Failed"; return; } } - LIMA
5个回答

14

简单来说,这样的运算符不存在,因此您无法重载它。

一个可能的解决方案是定义两个类: MatrixRow
您可以定义 Matrixoperator[],使其返回一个 Row,然后为 Row 定义相同的运算符,使其返回实际值(int 或任何您想要的类型,您的 Matrix 也可以是模板)。
这样,语句 myMatrix[row][col] 将是合法且有意义的。

同样的方法也可以用于将新的 Row 分配给 Matrix 或更改 Row 中的值。

* 编辑 *

根据评论的建议,您还应该考虑使用operator()而不是operator[]来处理这种情况。这样,就不再需要Row类了。

同时,您还应该考虑这一点。

我还要提到,重载运算符() 比重载[]更容易实现,可以返回一些带有自己运算符[]的自定义类。请参阅关于此问题的C++FAQ - Javier Martín
当然,这很有道理,但我理解OP的目标是使用类似myMatrix[row][col]的语句,这就是为什么我继续使用了operator[]的解决方案。无论如何,这是个好提示,我会修改回答的。 - skypjack
链接器如何区分ROW和Matrix的函数。它们都返回整数,签名相同。第一次运算符获取行索引并返回指向该行的指针(int),然后获取列索引(int)。 - LIMA
1
@lilach 是的,但它们属于不同的类。 :-) - skypjack
const int MyMatrix::operator[](const int index)const const int* Row::operator[](const int index)const请将以上两行代码翻译成中文。 - LIMA

9

您可以为类定义自己的 operator []。一个简单的方法可以按照以下方式实现:

#include <iostream>
#include <iomanip>

struct A
{
    enum { Rows = 3, Cols = 4 };
    int matrix[Rows][Cols];
    int ( & operator []( size_t i ) )[Cols]
    {
        return matrix[i];
    }
};

int main()
{
    A a;

    for ( size_t i = 0; i < a.Rows; i++ )
    {
        for ( size_t j = 0; j < a.Cols; j++ ) a[i][j] = a.Cols * i + j;
    }


    for ( size_t i = 0; i < a.Rows; i++ )
    {
        for ( size_t j = 0; j < a.Cols; j++ ) std::cout << std::setw( 2 ) << a[i][j] << ' ';
        std::cout << std::endl;
    }
}

程序输出为:
 0  1  2  3 
 4  5  6  7 
 8  9 10 11 

2
它之所以有效,是因为它返回了数组中选定行的引用,然后可以进一步使用[]进行索引 - 该类型是int & [Cols],这是在其衰变为指针之前matrix[i]的真实结果类型。然而,返回此类引用的函数语法非常丑陋且令人困惑,与成员函数指针处于同一级别,因此大多数人不费心思地只返回问题行的第一个元素的指针。 - Javier Martín
2
虽然我欣赏一些好的WAT,但我建议使用尾返回类型。 - MikeMB
1
@lilach matrix[i] 返回一个一维数组的引用。因此,您可以再次应用运算符[]以获取整数。也就是说,这个记录a[i][j]将是有效的。 - Vlad from Moscow
2
为了使定义更简单,您可以为返回类型引入别名或类型定义。例如,结构体A { 枚举{行=3,列=4}; 使用TRow = int(&)[Cols]; int矩阵[Rows] [Cols]; TRow operator [](size_t i) { 返回矩阵[i]; } }; - Vlad from Moscow
1
@lilach 或者以下方式。这样更清晰。结构体 A { enum { 行数 = 3, 列数 = 4 }; using TRow = int [列数]; int 矩阵[行数][列数]; TRow & operator []( size_t i ) { return 矩阵[i]; } }; - Vlad from Moscow
显示剩余3条评论

3

我不知道如何构建 operator [][]

有时使用另一个运算符即()是可以的:

int& Matrix::operator () (int x, int y)
{
    return matrix[x][y];
}

const int& Matrix::operator () (int x, int y) const
{
    return matrix[x][y];
}

int diagonal (const Matrix& m, int x)
{
    return m (x, x); // Usage.
}
优点:
  • 不需要使用像RowColumn之类的“中间”类。

  • 比使用Row& Matrix operator (int);更容易控制,因为有人可能会使用Row引用放入一个长度不合法的行。如果Matrix应该表示一个矩形物体(图像,代数中的矩阵),那么这是一个潜在的错误来源。

  • 在高维度下可能会更少枯燥乏味,因为operator[]需要所有较低维度的类。

缺点:
  • 语法不常见,与众不同。

  • 如果希望轻松替换完整行/列,则不能使用此方法。但是,无论如何,用行来模拟(反之亦然)替换列也不容易。

在任一情况下,如果在运行时未知维数,则存在优缺点。


1

我正在寻找经过自我测试的数组替换...改进版本返回引用或NULL引用,并在内部检查边界。

#include <iostream>
#include <iomanip>

template<typename T, int cols>
class Arr1
{
public:
    Arr1(T (&place)[cols]) : me(place) {};
    const size_t &Cols = cols;
    T &operator [](size_t i)
    {
        if (i < cols && this != NULL) return me[i];
        else {
            printf("Out of bounds !\n");
            T *crash = NULL;
            return *crash;
        }
    }
private:
    T (&me)[cols];
};
template<typename T, int rows, int cols>
class Arr2
{
public:
    const size_t &Rows = rows;
    const size_t &Cols = cols;
    Arr2() {
        ret = NULL;
        for (size_t i = 0; i < rows; i++) // demo - fill member array
        {
            for (size_t j = 0; j < cols; j++) matrix[i][j] = cols * i + j;
        }
    }
    ~Arr2() {
        if (ret) delete ret;
    }
    Arr1<T, cols>(&operator [](size_t i))
    {
        if (ret != NULL) delete ret;
        if (i < rows) {
            ret = new Arr1<T, cols>(matrix[i]);
            return *ret;
        }
        else {
            ret = NULL;
            printf("Out of bounds !\n");
            return *ret;
        }
    }
    //T(&MemberCheck)[rows][cols] = matrix;
private:
    T matrix[rows][cols];
    Arr1<T, cols> *ret;
};
template<typename T,int rows, int cols>
class Arr
{
public:
    const size_t &Rows = rows;
    const size_t &Cols = cols;
    T(&operator [](size_t i))[cols]
    {
        if (i < rows) return matrix[i];
        else {
            printf("Out of bounds !\n");
            T(*crash)[cols] = NULL;
            return *crash;
        }
    }
    T (&MemberCheck)[rows][cols] = matrix;
private:
    T matrix[rows][cols];
};

void main2()
{
    std::cout << "Single object version:" << endl;
    Arr<int, 3, 4> a;

    for (size_t i = 0; i <= a.Rows; i++)
    {
        int *x = &a[i][0];
        if (!x) printf("Fill loop - %i out of bounds...\n", i);
        else for (size_t j = 0; j < a.Cols; j++) a[i][j] = a.Cols * i + j;
    }

    for (size_t i = 0; i < a.Rows; i++)
    {
        for (size_t j = 0; j <= a.Cols; j++) {
            std::cout << std::setw(2) << a[i][j] << ' ';
            if (a.MemberCheck[i][j] != a[i][j])
                printf("Internal error !");
        }
        std::cout << std::endl;
    }

    std::cout << endl << "Double object version:" << endl;

    Arr2<int, 3, 4> a2;
    for (size_t i = 0; i < a2.Rows; i++)
    {
        for (size_t j = 0; j <= a2.Cols; j++) {
            int &x = a2[i][j];
            if (&x)
            {
                x++;
                std::cout << std::setw(2) << a2[i][j] << ' ';
                //if (&a2.MemberCheck[i][j] != &a2[i][j])
                //  printf("Internal error !");
            }
        }
    }
}

输出

Single object version:
Out of bounds !
Fill loop - 3 out of bounds...
 0  1  2  3  4
 4  5  6  7  8
 8  9 10 11 -858993460

Double object version:
 1  2  3  4 Out of bounds !
 5  6  7  8 Out of bounds !
 9 10 11 12 Out of bounds !

0

在下面的程序中它运行良好

#include<iostream>
using namespace std;
class A{
    public:
    int r,c;
    int** val;
    A()
    {
        r=0;c=0;val=NULL;
    }
    A(int row,int col)
    {
        r=row;c=col;
        int count=0;
        val=new int*[row];
        for(int i=0;i<r;i++){
            val[i]=new int[col];
            for(int j=0;j<c;j++){
                count++;
                val[i][j]=count;
            }
        }
    }
    int* &operator[](int index){
        return val[index];
    }
};
int main(void){
    A a(3,3);
    cout<<a[1][2];
    return 0;
}

在这里,a[1][2]首先计算a[1]-->它以(int*)类型返回第二行,然后被读取为(int*)[2],返回该行的第三个元素。简而言之,

a[1][2]------>(a[1])[2]------>(val[1])[2]------>val[1][2]。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接