转载:http://blog.youkuaiyun.com/keyouan2008/article/details/5773031
1-什么时候会用到拷贝构造函数?
2-什么时候有必要手动写拷贝构造函数?
1-什么时候会用到拷贝构造函数?
任何你想利用一个已有的类实例给另一个类实例赋值时,这种赋值可能是显式的,也可能是隐式的
显式:classa_1=class_2;
隐式:函数的形参有用到类对象却没有用引用或传址技术时
函数的返回值是一个对象也没有应用传址技术时
2-什么时候有必要用拷贝构造函数?
上述3种情况,如果没有涉及到深拷贝问题,就没有必要自己来编写拷贝构造函数,编译器有默认的可以很完美的完成任务
关于深拷贝
如果一个类中含有指针成员变量,则在利用一个已存在对象构造新的对象时,就会面临两种选择:深拷贝和浅拷贝。
浅拷贝只是将对象间对应的指针成员变量进行简单的拷贝,即拷贝结束后新旧对象的指针指向相同的资源(指针的值是相同的);这种拷贝会导致对象的成员不可用,如下例:
class Person
{
public :
//....
char * home; //the person's home
void SetHome(char * str)
{home = str;}
~Person()
{
//...
delete [] home;
}
}
//....
char * place = new char [20];
strcpy(place,"China");
Person *A = new Person();
A->SetHome(place);
Person * B= Person(A);
delete A;
//....
此时对象A 和对象B的成员home值相同,如果A对象 destroy,则对象B的成员home指向的地址变为不可用(对象A撤销时将home指向的资源释放了)。
深拷贝是相对于浅拷贝而言的,为了避免上述情况的发生,将上例中的代码改造:对象拷贝时将指针指向的内容拷贝,代码如下:
class Person
{
public :
//....
char * home;//the person's home
void SetHome(char * str)
{home = str;}
Person & Person(const Person & per)
{
//...
if(* this == per)//copy itself
return *this;
home = new char[strlen(per.home) +1]; //alloc new memory,深拷贝的体现
strcpy(home,per.home);
return * this;
}
~Person()
{
//...
delete [] home;
}
}
深拷贝之后,新旧对象的home成员指向的内容的值相同,而其自身的值不同。这样就可避免出现其中之一destroy 之后,另一对象的home成员不可用。【以上内容为转载】
这里补充一句,当类中包含了需要深拷贝的字符指针时,需要编写拷贝构造函数和赋值函数。
最后,以前面写的string类中的拷贝构造函数来结束。
string类必须要自己定义拷贝构造函数,而不能由编译器自动生成。因为m_string为指针,拷贝对象时需要为m_string分配内存空间,即深拷贝。
String::String(const String &str) { int len = strlen(str.m_string); m_string = new char[len+1]; //深拷贝的体现 strcpy(m_string,str.m_string); }
PS:拷贝构造函数的作用以及用途,什么时候需要自定义拷贝构造函数?
在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。 1). 一个对象以值传递的方式传入函数体 2). 一个对象以值传递的方式从函数返回 3). 一个对象需要通过另外一个对象进行初始化 以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作赋共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。 拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环。 除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。换句话说,你从函数返回得到的只是对象的一份拷贝。但是同样的,拷贝构造函数被正确的调用了,你不必担心。 如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会私下里为你制定一个函数来进行对象之间的位拷贝(bitwise copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。许多作者都会提及这个默认的拷贝构造函数。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对于成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数除非另外一个构造函数在类初始化或者在构造列表的时候被调用。 拷贝构造函数是程序更加有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统提供的帮助你申请内存默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。