【C++】重载二维数组下标 [ ][ ]

写在文章开头的话
读完这篇文章后,你将学习到下面的知识:
(1)一个多维数组是如何工作的
(2)如何重载二维数组下标

1. 分析


重载一维数组下标很简单,通过下标传入的索引值,返回内部数组中相应的值。那重载二维数组的下标运算呢?
其实重载二维和一维本质是一样的,因为 C/C++ 中所谓的 “二维或多维数组”都是由简单的一维数组表示的。举个例子哈:
下面是两个 int 数组,第(1)个是熟悉的一维数组,第(2)个是熟悉的二维数组,现在你要做的就是将第(2)个数组看成是一个一维数组。
(1)int array[3];          
(2)int array[3][4];
怎么看?可以在头脑中将第(2)个数组数组看成如下定义的方式, 数组 array 包含 3 个元素,其中每个元素又都是一个数组类型(或者说是一个指针类型)。
typedef int T[4];
T array[3];

至于更高维数的数组,也是这样看,比如如下的三维数组,可以采用下面的方式来定义。
int array[3][4][5];
typedef int T1[5];
typedef T1 T2[4];
T2 array[3];

由于实际中二维数组用的较多,所以,下面主要是练习二维数组的下标重载。那重载二维数组的下标有什么好处呢?最大的好处就在于可以使代码简洁直观。

我在网上也看到过一些别人的实现方法,其中在 文章( http://edu.gamfe.com/tutor/d/24416.html)中就提到了一种重载方法,使用一维数组来表示二维数组,这是大多数的实现方法,但是其实现过程过于复杂,其构建了两个类,分别用来获取行和列,然后计算出指定的二维下标对应的内部一维数组的值并返回。

下面介绍我自己写重载二维下标实现方式,不一定最好,但比上面提到的方式要好。

2. 重载固定维数的二维数组下标

对于固定维数的二维数组下标重载,一般在像3D图形方面经常涉及到一些平移转换矩阵时用到,这里以 4 * 4 的矩阵为例,实现代码如下:

struct Matrix4f
{
    float m[4][4];

    float * const operator[](const int i)
    {
        return m[i];
    }
};

测试赋值和取值操作,均正常:

Matrix4f m;
    m[0][0] = 1.0f;
    m[1][1] = 9.9f;
    cout << m[0][0] << endl;          // 1
    cout << m[1][1] << endl;          // 9.9

3. 重载维数可变的二维数组下标

对于可变的二维数组下标重载,在数组初始化时指定维数,之后可以像一般的二维数组进行赋值和取值操作,采用模板实现,代码如下:

template <typename T>
class Matrix
{
public:
    Matrix(int row, int col)
        :m_row(row), m_col(col), m_data(nullptr)
    {
        m_data = new T[m_row * m_col];
    }

    ~Matrix()
    {
        if (m_data != nullptr)
        {
            delete[] m_data;
            m_data = nullptr;
        }
    }
    
     // 返回二维数组的第 k 行地址
    T * operator[](int k)
    {
        return &m_data[k * m_col];
    }

private:
    int m_row;
    int m_col;
    T *m_data;
};

测试赋值和取值操作:

Matrix<int> m2(3, 4);
m2[0][0] = 2;
m2[2][3] = 9;
cout << m2[0][0] << endl;          // 2
cout << m2[2][3] << endl;          // 9

和一般的二维数组一样没有越界检查,所以越界操作也是可以的,但是尽量使用前检查索引是否越界,以免引发未知错误。


转载请注明出处:http://blog.youkuaiyun.com/xiaohui_hubei/article/details/21334141

C++中,通过重载下标运算符`[]`可以让用户自定义类型的对象像访问数组一样操作数据成员。对于二维数组来说,我们通常需要两次使用下标运算符来完成元素的定位。 ### 实现步骤 假设我们需要创建一个类 `Matrix` 来表示二维数组,并支持类似矩阵的操作: #### 示例代码 ```cpp #include <iostream> using namespace std; class Matrix { private: int rows; // 行数 int cols; // 列数 int** data; // 动态分配的二维数组 public: // 构造函数初始化二维数组 Matrix(int r, int c) : rows(r), cols(c) { data = new int*[rows]; for (int i = 0; i < rows; ++i) { data[i] = new int[cols]{}; } } // 拷贝构造函数、析构函数等省略... // 下标运算符的一级重载返回某一行 int* operator[](int rowIndex) { if (rowIndex >= rows || rowIndex < 0) throw out_of_range("Row index is out of range"); return data[rowIndex]; // 返回指向该行的指针 } // 获取列值的常量版本(防止修改) const int* operator[](int rowIndex) const { if (rowIndex >= rows || rowIndex < 0) throw out_of_range("Row index is out of range"); return data[rowIndex]; } ~Matrix() { // 析构函数释放动态内存 for (int i = 0; i < rows; ++i) delete[] data[i]; delete[] data; } void display() { for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { cout << (*this)[i][j] << " "; // 使用operator[] } cout << endl; } } }; int main() { Matrix m(3, 4); m[1][2] = 5; // 调用重载后的 [] 运算符设置值 m.display(); // 显示结果 try { cout << m[10][0]; // 测试越界检查 } catch (const exception& e) { cerr << e.what() << '\n'; // 输出错误信息 } return 0; } ``` --- ### 工作原理解析 1. **一级下标运算符** - 首先我们在类内重载了单个`[]`运算符,它接受一个整型作为索引参数。 - 我们将这一层理解为获取“某一维度”,即指定具体的行号并返回其对应的数据地址(如上例中的`data[rowIndex]`)。 2. **二级下标运算符** - 第一次调用了`matrixObj[index_row][]`, 得到的是指向当前行的一个指针;然后第二次直接对这个指针对应的内容应用普通的 C 数组语法 `[index_col]` 即可最终取得目标位置处存储的数据项。 3. **边界条件检测** - 当然,在实际项目里建议加入必要的异常处理机制以免发生非法存取的问题,比如超出预先设定大小等情况下的报错提示功能就显得尤为重要啦! ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值