复制构造函数
考虑下列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++高级主题