[C++]重载二维数组下标 [ ][ ]实现二维矩阵
1. 背景
实际项目中,经常需要用到动态分配二维数据。因此经常需要手写循环,来分配和初始化数组。如:
//首先分配一个指针数组
int** array = new int*[m];
//然后给指针数组中的指针分配内存
for (int i=0;i<m;i++)
{
for (int j=0;j<n;j++)
{
array[i] = new int[n];
}
}
虽然利用GSL等库可以完成相同的任务,但往往我们的项目中仅仅使用二维数组,并不需要复杂的矩阵运算;使用一维数组代替二维数组时,不能用array[i][j]的方式取值,没有二维数组直观。为了方便使用二维数组,本文使用一维数组,通过重载[]实现二维矩阵。
2. 分析
用一维数组代替二维数组分配内存,获得连续的内存空间。通过重载[],返回第K行地址,从而实现array[i][j]的方式取值。
3. 实现
#ifndef _MAT2_
#define _MAT2_
template <class T>
class Mat2
{
public:
typedef T value_type;
typedef T* pointer;
typedef T* const pointer_conster;
typedef const T& const_reference;
typedef const T* const const_pointer_const;
public:
typedef struct{
int cols;
int rows;
}Size2;
enum {ROW=1,COL=2};
public:
/**
*构造函数
*参数:行数rows、列数cols和初始化值defaul
*创建一个大小为rows*cols的矩阵,初始值全部为default
*/
Mat2(const int rows,const int cols,const_reference default=0);
/**
*构造函数
*参数:矩阵大小n和初始化值defaul
*创建一个大小为n*n的矩阵,初始值全部为default
*/
Mat2(const int n, const_reference default=0);
/**
*复制构造函数
*参数:矩阵
*/
Mat2(const Mat2& mat2);
~Mat2(void);
private:
int rows;
int cols;
pointer array;
public:
/**
*求矩阵大小
*返回值为Size2结构
*/
const Size2 size();
/**
*求矩阵大小
*参数值为Mat2:ROW或者Mat2:COL
*参数值为Mat2:ROW时返回行数;位Mat2:COL时返回列数,否则返回-1
*/
const int size(int type) const;
/**
*返回一维数组
*/
const_pointer_const data(){return array;}
/**
*重载赋值运算符
*/
Mat2& operator=(const Mat2& mat);
/**
*重载[]运算符
*/
pointer_conster operator[](const int k);
//用default值填充矩阵
void fill(const_reference default);
};
//注意:在模板中使用嵌套名字时,需要用typename关键字区分::取得是类型还是静态变量
template<class T>
Mat2<T>::Mat2(const int m,const int n,typename Mat2<T>::const_reference default)
:rows(m),cols(n),array(new value_type[rows*cols])
{
fill(default);
}
template<class T>
Mat2<T>::Mat2(const int n,typename Mat2<T>::const_reference default)
:rows(n),cols(n),array(new value_type[n*n])
{
fill(default);
}
template<class T>
Mat2<T>::Mat2(const Mat2& mat)
{
Mat2::Size2 size2 = mat.size();
rows = size2.rows;
cols = size2.cols;
array = new value_type[rows*cols];
memcpy(array,mat.data(),rows*cols*sizeof(value_type));
}
template<class T>
const typename Mat2<T>::Size2 Mat2<T>::size()
{
Mat2::Size2 size2;
size2.rows = rows;
size2.cols = cols;
return size2;
}
template<class T>
const int Mat2<T>::size(int type) const
{
switch(type)
{
case Mat2::ROW:
return rows;
case Mat2::COL:
return cols;
}
return -1;
}
template<class T>
typename Mat2<T>& Mat2<T>::operator =(const Mat2<T>& mat)
{
if (this != &mat)//注意:防止自复制
{
if (array)
{
delete[] array;
}
Mat2::Size2 size2 = mat.size();
rows = size2.rows;
cols = size2.cols;
array = new value_type[rows*cols];
memcpy(array,mat.data(),rows*cols*sizeof(value_type));
}
return *this;
}
// 返回二维数组的第 k 行地址,注意加上 const 因为数组地址是不可变的
template<class T>
typename Mat2<T>::pointer_conster Mat2<T>::operator[](const int k)
{
return &(array[k*cols]);
}
template<class T>
void Mat2<T>::fill(typename Mat2<T>::const_reference default)
{
for (int i=0;i<rows;i++)
{
for (int j=0;j<cols;j++)
{
array[i*cols+j] = default;
}
}
}
template<class T>
Mat2<T>::~Mat2(void)
{
if (array)
{
delete[] array;
}
}
#endif // _MAT2_