拷贝构造函数和赋值构造函数的区别
这两种函数什么时候用呢?
1、当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。
2、一个对象以值传递的方式传入函数体
3、一个对象以值传递的方式从函数返回
4、一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象
之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。
自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
例子:
String a("Copy");
String b("Assign");
String c = a; // 调用了拷贝构造函数,最好写成 c(a)。
c = b; // 调用了赋值构造函数。
本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
注意:拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。
不同点:
拷贝构造函数:首先是一个构造函数,它调用的时候产生一个对象,是通过参数传进来的那个对象来初始化,产生的对象。
赋值构造函数:是把一个对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检查
一下两个对象是不是同一个对象,如果是的话就不做任何操作。
注意的是拷贝构造函数是构造函数,不返回值;而赋值函数需要返回一个对象自身的引用,以便赋值之后的操作。
浅拷贝和深拷贝
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。
这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放
了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的
时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。
浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错。
下面是例子,使用 C++ Builder 2009 编译
#include <iostream>
#include <tchar.h>
#include <conio.h>
#pragma argsused
using namespace std;
class HJQ{
public:
HJQ(int len,char* cstr){
int clen = strlen(cstr);
if( 0 != clen){ //此处应当检查cstr的长度,防止缓冲区溢出或者数组越界
_len = clen > len ? len : clen;
_str = new char[_len+1]; //注意这里要多分配一个字节
memcpy(_str,cstr,_len);
_str[_len] = '\0';
}else{
_len = 0;
}
}
HJQ(const HJQ& Other){ //拷贝构造函数
_len = Other._len;
if( 0 != _len){
_str = new char[_len+1]; //深拷贝
memcpy(_str,Other._str,_len);
_str[_len] = '\0';
}
}
HJQ& operator = (const HJQ& Other){ //赋值符重载
// (1) 检查自赋值
if(this == &Other)
return *this;
_len = Other._len; //复制常规成员
// (2) 释放原有的内存资源
if(_str)
delete []_str;
if( 0 == _len)
return *this;//判断长度是否为零
// (3) 分配新的内存资源,并复制内容
_str = new char[_len+1];
memcpy(_str,Other._str,_len);
_str[_len] = '\0';
// (4) 返回本对象的引用
return *this;
}
void Show(){
cout<<_str<<endl;
}
~HJQ(){
delete []_str;
}
private:
int _len;
char *_str;
//如果不想编译器自动生成拷贝构造函数和复制构造函数,也不想使用这两种构造函数
//可将其声明为私有函数,但是却不实现它。一旦代码中有使用拷贝构造函数或者赋值
//构造函数的地方,链接器就会报错!
//HJQ(int len,char* cstr);
//HJQ& operator = (const HJQ& Other);
};
int _tmain(int argc, _TCHAR* argv[]){
HJQ A(10,"Hello!");
HJQ B = A;
B.Show();
HJQ C(100,"world!");
C = B;
getch();
return 0;
}