为对象动态分配内存

如果类中的数据成员含有指针变量,就需要为指针变量分配动态内存。(通常在编程中,应该尽量避免使用指针,应该用容器替代指针)

在本例中,使用二重指针,可以视为一个二维数组,不过该数组的元素个数可变。

如下为为指针分配空间的构造函数;

//构造函数,创建一个可以指定长度和高度的二维数组
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;
}

猜你喜欢

转载自blog.csdn.net/makesifriend/article/details/84784782
今日推荐