为什么叫拷贝构造器不叫拷贝构造函数就不重复说了,构造器部分有说明。拷贝构造器的格式如下:
类名(const 类名 & another){}
即是用一个已经存在的对象去创建一个不存在的对象,编译器也会生成一个默认的拷贝构造器,默认拷贝构造器是浅拷贝,如果自定义了拷贝构造器,那么编译器便不会自动生成拷贝构造器,比如:
class A{
private:
char *str;
public:
A(const A & another){ //拷贝构造器
str = another.str; //同类之间不存在隐私,故another此刻可以访问私有成员str
}
}
用下面代码调用:
A another;
A new_object(another);
代码中的虽然自定义了拷贝构造器,但只是用来展示默认的拷贝构造器就是长这么个模样的。也就是说:
上面的another是已经存在的对象,new_object是要创建的对象,用默认拷贝构造器,也就是说浅拷贝,new_object与another都有一个4字节的内存空间,new_object在创建是等位拷贝another空间中的东西,也就是说把another空间里的“12abcdef”一位一位的拷贝到了new_object的内存空间中,这样两者都指向str,也就是说,如果改了another, new object也会变,同理,如果改变了new object ,another也会变。正因为两者共同指向同一块内存,那么当空间释放的时候,必定会造成同一块内存空间释放两次的情况,叫做重析构,可能在有的编译器上不会提示错误,但在linux一般编译就不会通过。
如果想让新创建的对象和已经存在的对象分别有自己的内存空间该怎么做呢?
此时的拷贝构造器应该这样写:
class A{
private:
char *str;
public:
A(const A & another){ //拷贝构造器
int len = strlen(another.str);
str = new char[len]; //为成员创建新的内存空间
strcpy(str, another.str);
}
}
此时的内存示意图如下:
这样new_object为自己的str开辟了一段内存空间,只不过再把another.str的内容复制过来就可以了,如此,两者的修改就不会相互影响了。
对于如下的对象间复制操作:
A another;
A new_object = another;
其实这个的本质也是拷贝构造器
还有一个也是个拷贝构造器的例子:
void func(A a){
}
int main(){
A x;
func(x); //这时候也是拷贝构造
}
main函数中发生了一次构造,一次拷贝构造,两次析构。