如果类中的数据成员含有指针变量,就需要为指针变量分配动态内存。(通常在编程中,应该尽量避免使用指针,应该用容器替代指针)
在本例中,使用二重指针,可以视为一个二维数组,不过该数组的元素个数可变。
如下为为指针分配空间的构造函数;
//构造函数,创建一个可以指定长度和高度的二维数组
SpreadSheet::SpreadSheet(int height, int length)
{
mCells = new SpreadCell* [length];
for(int i = 0; i < length; i++)
{
mCells[i] = new SpreadCell[height];
}
}
在此构造函数中,想为指针数组分配空间,在为每个指针数组中的元素分配空间。
释放指针空间的析构函数定义如下:
//析构函数,先删除length个一维指针,再删除一个二维指针
SpreadSheet::~SpreadSheet()
{
for(int i = 0; i < length; i++)
{
//mCells[i]是指针数组首地址,删除此指针数组中的所有元素。
delete [] mCells[i];
}
delete mCells;
}
由于mCells[i]相当于一个指针数组的头地址,mCells[i][0-j]都对应一个元素,所以删除该指针使用了删除数组指针的方法
delete [] mCells
删除指针数组之后,再删除该指向该指针数组的指针mCells。
默认情况下,在含有指针数组的对象中,对象的复制是浅复制,容易形成野指针。避免这种情况的话,就要在对象复制之前,先为对象分配空间,进行深复制。对象的赋值与此类似。以下代码为对象的复制操作。
//复制构造函数
SpreadSheet::SpreadSheet(const SpreadSheet& src)
{
copyFrom(src);
}
其中,copyFrom(src)为辅助函数,不仅分配内存,还为内存里的元素赋值。其定义如下:
//辅助copy函数
void SpreadSheet::copyFrom(const SpreadSheet& src)
{
height = src.height;
length = src.length;
//分配length个堆空间,每个堆空间存储一个指向SpreadCell的指针
mCells = new SpreadCell* [length];
for (int i = 0; i < length; i++)
{
//分配height个堆空间,每个堆空间存储一个SpreadCell对象。
mCells[i] = new SpreadCell[height];
}
for(int i = 0; i < length; i++)
{
for(int j = 0; j < height; j++)
{
mCells[i][j] = src.mCells[i][j];
}
}
}
上述代码就是先为本对象分配空间,在给对象内的空间赋值,很容易理解。如下为对象赋值的定义,在copyFrom之前,先进行了自赋值判断。
//对象赋值
SpreadSheet& SpreadSheet::operator =(const SpreadSheet& rhs)
{
if(this == &rhs)
{
return *this;
}
else
{
copyFrom(rhs);
return *this;
}
}
整体程序如下所示:
#include <iostream>
#include <string>
using namespace std;
class SpreadCell
{
private:
int value;
public:
SpreadCell(): value(0) {};
SpreadCell(int a): value(a) {};
void setValue(const int& a);
int getValue() const;
};
//赋值给其它值的形参都可以这样定义
void SpreadCell::setValue(const int &a)
{
value = a;
}
//const的作用,保证该函数不修改数据成员
int SpreadCell::getValue() const
{
return value;
}
class SpreadSheet
{
private:
int height;
int length;
SpreadCell **mCells;
void copyFrom(const SpreadSheet &src);
public:
//~ SpreadSheet();
SpreadSheet(int height = 4, int length = 5);
SpreadSheet(const SpreadSheet& src);
virtual ~SpreadSheet();
SpreadSheet& operator = (const SpreadSheet& rhs);
void setValue(const int& x, const int& y, const SpreadCell& cell);
SpreadCell getValue(const int& x, const int& y);
};
//构造函数,创建一个可以指定长度和高度的二维数组
SpreadSheet::SpreadSheet(int height, int length)
{
mCells = new SpreadCell* [length];
for(int i = 0; i < length; i++)
{
mCells[i] = new SpreadCell[height];
}
}
//辅助copy函数
void SpreadSheet::copyFrom(const SpreadSheet& src)
{
height = src.height;
length = src.length;
//分配length个堆空间,每个堆空间存储一个指向SpreadCell的指针
mCells = new SpreadCell* [length];
for (int i = 0; i < length; i++)
{
//分配height个堆空间,每个堆空间存储一个SpreadCell对象。
mCells[i] = new SpreadCell[height];
}
for(int i = 0; i < length; i++)
{
for(int j = 0; j < height; j++)
{
mCells[i][j] = src.mCells[i][j];
}
}
}
//复制构造函数
SpreadSheet::SpreadSheet(const SpreadSheet& src)
{
copyFrom(src);
}
//对象赋值
SpreadSheet& SpreadSheet::operator =(const SpreadSheet& rhs)
{
if(this == &rhs)
{
return *this;
}
else
{
copyFrom(rhs);
return *this;
}
}
//析构函数,先删除length个一维指针,再删除一个二维指针
SpreadSheet::~SpreadSheet()
{
for(int i = 0; i < length; i++)
{
//mCells[i]是指针数组首地址,删除此指针数组中的所有元素。
delete [] mCells[i];
}
delete mCells;
}
//在指定位置定义元素
void SpreadSheet::setValue(const int& x, const int& y, const SpreadCell& cell)
{
mCells[x][y] = cell;
}
//读取指定位置的元素
SpreadCell SpreadSheet::getValue(const int& x, const int& y)
{
return mCells[x][y];
}
int main()
{
SpreadCell a, cell;
a.setValue(2);
SpreadSheet sc(4, 5);
sc.setValue(1, 2, a);
cell = sc.getValue(1, 2);
SpreadSheet sc2(sc), sc3;
sc3 = sc;
cout << "value:" << cell.getValue() << endl;
}