当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 关于拷贝构造函数和赋值运算符

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 关于拷贝构造函数和赋值运算符


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 103 ::
收藏到网摘: n/a

关于拷贝构造函数和赋值运算符
作者:冯明德


重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。

以下讨论中将用到的例子:

class CExample{public:	CExample(){pBuffer=NULL; nSize=0;}	~CExample(){delete pBuffer;}	void Init(int n){ pBuffer=new char[n]; nSize=n;}private:	char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源	int nSize;};

这个类的主要特点是包含指向其他资源的指针。

pBuffer指向堆中分配的一段内存空间。

一、拷贝构造函数

int main(int argc, char* argv[]){	CExample theObjone;	theObjone.Init40);	//现在需要另一个对象,需要将他初始化称对象一的状态	CExample theObjtwo=theObjone;	...}

语句"CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。

其完成方式是内存拷贝,复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。

所以需要采用必要的手段来避免此类情况。

回顾以下此语句的具体过程:首先建立对象theObjtwo,并调用其构造函数,然后成员被拷贝。

可以在构造函数中添加操作来解决指针成员的问题。

所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,上面的语句中,如果类中定义了拷贝构造函数,这对象建立时,调用的将是拷贝构造函数,在拷贝构造函数中,可以根据传入的变量,复制指针所指向的资源。

拷贝构造函数的格式为:构造函数名(对象的引用)

提供了拷贝构造函数后的CExample类定义为:

class CExample{public:	CExample(){pBuffer=NULL; nSize=0;}	~CExample(){delete pBuffer;}	CExample(const CExample&); //拷贝构造函数	void Init(int n){ pBuffer=new char[n]; nSize=n;}private:	char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源	int nSize;};CExample::CExample(const CExample& RightSides) //拷贝构造函数的定义{	nSize=RightSides.nSize; //复制常规成员	pBuffer=new char[nSize]; //复制指针指向的内容	memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));}

这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample& RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。

原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。

拷贝构造函数的另一种调用。

当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。

例如

BOOL testfunc(CExample obj);testfunc(theObjone); //对象直接作为参数。BOOL testfunc(CExample obj){	//针对obj的操作实际上是针对复制后的临时拷贝进行的}

还有一种情况,也是与临时对象有关的

当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用

CTest func(){	CTest theTest;	return theTest}

二、赋值符的重载

下面的代码与上例相似

int main(int argc, char* argv[]){	CExample theObjone;	theObjone.Init(40);	CExample theObjthree;	theObjthree.Init(60);	//现在需要一个对象赋值操作,被赋值对象的原内容被清除,并用右边对象的内容填充。	theObjthree=theObjone;	return 0;}

也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。

例如 CExample theObjone(theObjtwo);

而本例子中,"="表示赋值操作。将对象theObjone的内容复制到对象theObjthree;,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。

但"="的缺省操作只是将成员变量的值相应复制。旧的值被自然丢弃。

由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未复制。

因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值操作符号。

类定义变为:

class CExample{	...	CExample(const CExample&); //拷贝构造函数	CExample& operator = (const CExample&); //赋值符重载	...};
//赋值操作符重载CExample & CExample::operator = (const CExample& RightSides){	nSize=RightSides.nSize; //复制常规成员	char *temp=new char[nSize]; //复制指针指向的内容	memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));	delete []pBuffer; //删除原指针指向内容 (将删除操作放在后面,避免X=X特殊情况下,内容的丢失)	pBuffer=temp; //建立新"