当程序生成了对象副本的时候,编译器就会自动调用拷贝(复制)构造函数。
在C++类的成员变量中存在指针变量的时候,就会存在深拷贝和浅拷贝问题。当使用C++编译器默认提供的拷贝构造函数或者对象的赋值操作的时候就会出现浅拷贝,而导致在析构的时候出错。
如在下述代码中,当创建一个对象时调用构造函数分配内存进行初始化,但是①在没有手动编写拷贝构造函数时,用一个对象去初始化新对象时,C++编译器完成的是浅拷贝,只是简单地对变量进行赋值,而对指针变量进行简单赋值只是将地址赋给新对象的指针变量,这样两个对象的指针变量指向同一块内存空间。这样根据析构函数的析构顺序,新对象析构掉的时候将内存释放了,就对象析构的时候就会导致内存访问出错。②在没有手动编写等号运算符重载函数时,原理和上述①一样。
system("pause");return 0;} 若没有为Name类提供拷贝构造函数和等号运算符重载函数则在析构的时候将报错。因此Name类提供以下拷贝构造函数和等号运算符重载函数class Name { public: Name(const char *str) { len = strlen(str); name = new char[len + 1]; *(name + len) = '\0'; memcpy(name, str, len); } ~Name() { if (name != NULL) { delete[]name; name = NULL; len = 0; } } void Print() { cout << "The name is :" << name << endl; } private: char *name; int len; }; int main() { Name n1("Micheal"); Name n2 = n1;//使用n1对象初始化一个新对象。调用拷贝构造函数 Name n3; n3 = n1;//使用赋值操作,调用“=”重载函数 n2.Print(); n1.Print(); <pre name="code" class="cpp"> n3.Print();
//拷贝构造函数 Name(const Name& n) { len = strlen(n.name); name = new char[len + 1]; memcpy(name, n.name, len); *(name + len) = '\0'; }
//等号运算符重载函数 void operator=(const Name& n) { if (name != NULL) { delete[]name; name = NULL; len = 0; } len = strlen(n.name); name = new char[len + 1]; memcpy(name, n.name, len); *(name + len) = '\0'; }
总结:
当程序中存在以下几种情况的时候调用拷贝构造函数
①用一个现有类对象去显式初始化新对象的时候
②函数按值传递对象或者返回对象的时候
③编译器生成临时对象时,如将三个对象相加,编译器可能生成临时对象。
当函数中存在指针变量等地址操作时必须手动编写复制构造函数和赋值操作符重载函数,否则编译器调用编译器自己提供的拷贝构造函数或者赋值操作符重载函数时在析构的时候容易出错。