C++封装学习(二)

对象数组的实例。

class Coordinate
{
public:
	int m_iX;
	int m_iY;
};

int main()
{
	Coordinate coord[3];//栈中实例化
	coord[1].m_iX = 10;
	Coordinate *p = new Coordinate[3];//堆中实例化
	p[0].m_iY = 20;			p->m_iY = 20
	delete[]p;
	p = NULL;
	return 0;
}


用new申请数组空间后,要用delete []p来释放掉内存,那为什么要加[]呢。

在申请一个对象数组时,分别调用了n次的构造函数,在释放时也要调用n次析构函数,如果不加[],那么只销毁指针指向的第一个元素。


在实际应用中,对象中包含对象是很常见的,如一个房间有桌子等家具。以下为代码实例。

class Coordinate//坐标系上的点
{
public:
	Coordinate();
private:
	int m_iX;
	int m_iY;
};

class Line//坐标系上的线
{
public:
	line();
private:
	Coordinate m_coorA;
	Coordinate m_coorB;
};

int main()
{
	Line *p = new Line();

	delete p;
	p = NULL;
	return 0;
}
那么,在实例化对象时,是先实例化点还是先实例化线呢》

在实例化线时,先实例化A,再实例化B,最后实例化Line。销毁时正好与创建的过程相反。


拷贝构造函数分为深拷贝和浅拷贝。一个浅拷贝的实例代码。

class Array
{
public:
	Array(){ m_iCount = 5; m_pArr = new int[m_iCount]; }//构造函数,指向堆申请的内存
	Array(const Array& arr)//拷贝构造函数
	{
		m_iCounta = arr.m_iCount;
		m_pArr = arr.m_pArr;
	}
private:
	int m_iCount;
	int *m_pArr;//指针
};

int main()
{
	Array arr1;
	Array arr2 = arr1;//这种情况下,浅拷贝
	return 0;
}

这种情况很危险,因为两个指针指向统一内存,当改变arr1的内存,arr2的内容也势必会被改变,当释放arr1时,arr2也会释放,会引起崩溃。因此要实现深拷贝,即两个指针指向不同的内存,如图。


要实现深拷贝,代码如下。

class Array
{
public:
	Array(){ m_iCount = 5; m_pArr = new int[m_iCount]; }//构造函数,指向堆申请的内存
	Array(const Array& arr)//拷贝构造函数,深拷贝
	{
		m_iCounta = arr.m_iCount;
		m_pArr = new int[m_iCount];
		for (int i = 0; i < m_iCount; i++)
		{
			m_pArr[i] = arr.m_pArr[i];
		}
	}
private:
	int m_iCount;
	int *m_pArr;//指针
};

int main()
{
	Array arr1;
	Array arr2 = arr1;//这种情况下,浅拷贝
	return 0;
}


对象指针,就是指针指向一个对象。


class Coordinate//坐标系上的点
{
public:
	int m_iX;
	int m_iY;
};

Coordinate *p = new Coordinate;//在堆中实例化


在实例化是,p的指针实际指向的是m_iX,在实例化对象时,下列代码中的注释部分也是符合语法的。

int main()
{
	Coordinate *p = new Coordinate;//在堆中实例化
	p->m_iX = 10;//(*p).m_iX=10;
	p->m_iY = 20;//(*p).m_iY=20;
	delete p;
	p = NULL;
	return 0;
}

对象成员指针,在累的成员中包含指针,如下代码。

class Coordinate//坐标系上的点
{
public:
	Coordinate(int x, int y);
private:
	int m_iX;
	int m_iY;
};

class Line//坐标系上的线
{
public:
	Line();
	~Line();
private:
	Coordinate *m_pCoorA;
	Coordinate *m_pCoorB;
};


在构造函数时,可以初始化列表构造,也可以普通构造,因为是指针,所以可以置为NULL。

Line::Line() :m_pCoorA(NULL), m_pCoorB(NULL)//初始化列表初始
{

}

Line::Line()//普通初始化
{
	m_pCoorA=NULL;
	m_pCoorB=NULL;
}

当然更一般的是赋予指针值。

Line::Line()//普通初始化
{
	m_pCoorA=new Coordinate(1,3);
	m_pCoorB=new Coordinate(5,6);
}

Line::~Line()
{
	delete m_pCoorA;
	delete m_pCoorB;
}

特别值得注意的是,如果用sizeof查看line的话,那么打印出为8,因为每个指针地址是4个内存单元。而不是16(4个int)。


this指针。

一般来说,类函数的传递参数和成员不同名,如下代买所示。

class Array
{
public:
	Array(int _len){ len = _len; }
	int getLen(){ return len; }
	void setLen(int _len){ len = _len; }
private:
	int len;
};

那么,如果同名的话,会发生什么,如下代码,编译器会报错,因为无法分辨哪个是作为参数的Len。

class Array
{
public:
	Array(int len){ len = len; }
	int getLen(){ return len; }
	void setLen(int len){ len = len; }
private:
	int len;
};

因此,我们需要一种技术来标注出参数或者标注出数据成员。这就是this指针。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值