C++高级主题之复制构造函数

复制构造函数

    考虑下列Department类型变量的定义:

Department dept=qc;

尽管这个定义看起来像赋值,但operator=函数并没有发挥作用。operator=函数的目的就是用一个已有的对象赋给另外一个对象。然而,此时对象dept还是没有被构造,即指针dept.address只存放了一个随机值。如果回顾operator=函数的实现代码,就会注意到其第一部分代码删除了address指针所指向的原有对象。如果用一个未初始化的对象来执行operator=函数,就会引发致命错误,因为它试图删除一个未被初始化的指针,这将导致程序崩溃或者动态内存冲突。

实际上,编译程序将调用另一个内存管理函数---复制构造函数。它定义怎样将类的一个对象作为另一个对象的副本来构造一个对象。

如果用户没有定义复制构造函数,编译程序将提供一个默认的复制构造函数,它只是把已有对象的数据成员复制给新建对象的对应数据成员。对于类Department来说,其默认复制构造函数应包括如下动作:

 dept.name=qc.name;

strcpy(dept.address,qc.address);

但是,该复制构造函数有问题,它将会导致与默认赋值运算符函数同样的错误。所以,必须定义一个复制构造函数,以便创建一个address的一个副本。

下面是Department类的一个复制构造函数:

Department::Department(const Department& b)
{
cout<<"复制构造函数:";
b.print();
name=b.name;
if(b.address==NULL)
address=NULL;
else
{
address=new char[strlen(b.address)+1];
name=b.name;
strcpy(address,b.address);
}
}
赋值运算符函数、复制构造函数和析构函数是较为重要的三个部分。在任何涉及动态内存管理的类中必须实现它们。

正如Marshall Cline所说:“它不仅仅是个好主意,它是法律”。当这个法律变得和税法一样并且被人接受时,遵守起来也就不难了。定义这三个函数时应采用下面的逻辑步骤:

析构函数(Destructor)

    释放对象所管理的所有动态内存。

复制构造函数(Copy Constructor)

   用显示参数对象的副本来初始化对象。

赋值运算符函数(Assignment Operator)

   测试this==&b是否为真。如果为真,则什么也不做。

   释放不再需要的对象的动态内存。

   将对象设置为显示参数对象的一个副本。

   返回*this。

注意:如果是在用户自定义的类中管理动态内存,则需要考虑这三个函数。如果使用类库如vector或list,就不必考虑这些,

因为,这些类都已实现了这三个相应的函数。

下面是类Department中这三个函数的内存管理程序的测试程序。为了测试,内存管理程序将显示跟踪信息。

#include<string>
#include<iostream>
using namespace std;
class Department
{
public:
	Department(string _name);
	Department(string _name,char* _address);
	~Department();
	Department& operator=(const Department& b);
	Department(const Department &b);//复制构造函数
	void print()const;
private:
	string name;
	char* address;
};
Department::Department(string _name)
{
	name=_name;
	address=NULL;
	cout<<"Constructor:";
	print();
}
Department::Department(string _name,char* _address)
{
	name=_name;
	address=new char[strlen(_address)+1];
	strcpy(address,_address);
	cout<<"Constructor:";
	print();
}
Department::~Department()
{
	cout<<"Destructor:";
	print();
	delete []address;
}
Department::Department(const Department& b)
{
	cout<<"复制构造函数:";
	b.print();
	name=b.name;
	if(b.address==NULL)
		address=NULL;
	else
	{
		address=new char[strlen(b.address)+1];
		name=b.name;
		strcpy(address,b.address);
	}
}
Department& Department::operator=(const Department& b)
{
	cout<<"Assignment:";
	print();
	cout<<"= ";
	b.print();
	if(this != &b)
	{
		name=b.name;
		delete[] address;
		if(b.address==NULL)
		    address=NULL;
	    else
		{	
			address=new char[strlen(b.address)+1];
		    name=b.name;
		    strcpy(address,b.address);
		}
	}
    return *this;
}
void Department::print()const
{
	cout<<"name="<<name<<",address=";
	if(address==NULL)
		cout<<"NULL";
	else
		cout<<address;
	cout<<"\n";
}
/*
void fun(Department x)
{
   string p=x.name;//error cannot access private variable
}*/
void main()
{
	Department shipping("shipping");
	Department qc("quality control","china");
	Department dept(qc);
	dept=shipping;
}

程序运行结果:

程序有三个构造函数调用和三个匹配的析构函数调用。

摘自:C++核心思想 C++高级主题

原文地址:https://www.cnblogs.com/wintergrass/p/2051515.html