如何自定义拷贝构造函数

如何自定义C++中的拷贝构造函数,什么时候需要自定义拷贝构造函数,为什么?

一般而言,当你需要自定义析构函数的时候,你就需要自定义拷贝构造函数以及赋值运算符重载。
析构函数一般在涉及到需要手动释放系统资源的时候就需要自定义,典型的例子就是指针。

当你需要进行对象赋值初始化的时候,就需要定义拷贝构造,对于C++来说,这是经常发生的,所以自定义类一般都需要定义拷贝构造函数

//自定义拷贝构造函数
classname(const classname &ob)
{
//自定义拷贝构造函数的函数体
}
// 其中ob是用来初始另一个对象的对象的引用

class StringData{
private: char *str;
public:
StringData(char *s){

str=new char[strlen(s)+1];
strcpy(str,s);
}
StringData(const StringData &p){
str=new char[strlen(p.str)+1];
strcpy(str,p.str);
}
~StringData() { delete str; }
//…
};
int main()
{

StringData x(“abc”);

StringData y(x);
}


拷贝构造函数是一种特殊的构造函数。它用于依据已存在的对象建立一个新对象。
如果一个对象里面有指针成员,并且这个指针已经动态分配空间了,同时,对象有析构函数对这个指针进行释放。如上面那个例子,如果我们通过这个对象创建一个新对象:
A a("123");
A b = a; // 调用拷贝构造函数

如果我们没有自定义拷贝构造函数,导致对象 a 和 b 的指针成员指向同一个地址空间,当对象生命周期结束时,a 和 b 都会调用析构函数,最后导致,这个指针会被释放 2 次,导致内存出问题。

所以,对象有指针成员,尽量自定义拷贝构造函数。

  //自定义拷贝构造函数
classname(const classname &ob)
{
    //自定义拷贝构造函数的函数体
} 
// 其中ob是用来初始另一个对象的对象的引用

class StringData{
private: char *str;
public:
    StringData(char *s){
        str=new char[strlen(s)+1];
        strcpy(str,s);
    }
    StringData(const StringData &p){ // 拷贝构造函数
            str=new char[strlen(p.str)+1];
            strcpy(str,p.str);
    }
    ~StringData() { delete str; }
    //…
}; 
int main()
{

    StringData x(“abc”);
    StringData y(x);
}

拷贝构造函数是一种特殊的构造函数。它用于依据已存在的对象建立一个新对象。

如果一个对象里面有指针成员,并且这个指针已经动态分配空间了,同时,对象有析构函数对这个指针进行释放。如上面那个例子,如果我们通过这个对象创建一个新对象:
A a("123");
A b = a; // 调用拷贝构造函数

如果我们没有自定义拷贝构造函数,导致对象 a 和 b 的指针成员指向同一个地址空间,当对象生命周期结束时,a 和 b 都会调用析构函数,最后导致,这个指针会被释放 2 次,导致内存出问题。

所以,对象有指针成员,尽量自定义拷贝构造函数。

估计那些抄来的答案你也不爱看,我说重点:

要回答这个问题,就要先搞清楚默认的拷贝构造函数都干了什么。
默认的拷贝构造函数很简单,就是把对象中的每个字段又复制了一遍。
看这个例子:
class User
{
public : char * UserName;
}
很简单,一个User对象,里面包括一个UserName的字符串的字符指针。
如果我们不实现自己的拷贝构造函数,会如何?
C++会直接拷贝一份形成一个新的对象,这意味着,UserName的指针原样搬到了新的对象中。那么好了,你修改新的对象的UserName,原来的对象跟着变了。
那么怎么做才是正确的呢?我们应该重新分配一个空间,将UserName的值复制过来,而不是简单的复制指针。使得新的对象拥有一个UserName内容一样但是全新的指针。
明白了么?
更多概念,请google:浅拷贝 深拷贝

新建一个对象并将其初始化为同类现有对象时将调用复制构造函数,最常见的是将新对象显示的初始化为现有 的对象,可以参考C++ Primary Plus 第12章