1. 什么是拷贝构造函数
拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用在函数调用时用户定义类型的值传递及返回。其形式为:Test(const Test& obj),拷贝构造函数的名称必须与类名称一致,函数的形式参数是本类型的一个引用变量,且必须是引用。
2. 什么情况下调用拷贝构造函数
对于普通类型的对象来说,它们之间的复制是很简单的,是简单的浅拷贝,例如:int a=15;int b= a;而类的对象之间赋值复杂些。
在C++中,下面三种对象需要调用拷贝构造函数:
1) 一个对象以值传递的方式传入函数体;
2) 一个对象以值传递的方式从函数返回;
3) 一个对象需要通过另外一个对象进行初始化;
如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间,拷贝构造函数不可以改变它所引用的对象。
3. 什么情况下需要定义拷贝构造函数
设计拷贝构造函数是一个良好的风格,即使是编译系统会自动为你生成默认拷贝构造函数。对于没有指针成员的类,可以不定义拷贝构造函数,编译器会给你定义一个默认的拷贝构造函数实现按位拷贝的形式实现。
但是对于有指针成员的类,最好定义拷贝构造函数,如果这种情况下,让编译器给定义个拷贝构造函数,也实现位拷贝(浅拷贝)的话,会使得后来构造的对象和原来的对象的指针成员指向同一内存,如果原来的对象析构掉了,则后来构造的对象的指针成员则成了野指针。
示例:
#include "stdafx.h"
#include "string.h"
class A
{
public:
A(int n)
{
a = n;
}
A(const A&n) //有指针成员的话,对象相互赋值,必须自定义拷贝构造函数
{
//自定义拷贝构造函数
a = n.a;
printf("%d",n.a);
pBuf = new char[a]; //实现深拷贝
strcpy(pBuf,n.pBuf);
printf("拷贝构造函数被调用!");
}
void Init(int m)
{
a = m;
pBuf = new char[m];
memcpy(pBuf,"aaaa",5);
}
~A()
{
delete pBuf;
}
public :
int a;
char *pBuf; //类的对象中包含指针,指向动态分配的内存资源
};
int main()
{
A obj1(20); //C++中对象不用new,直接声明,区别C#
obj1.Init(30);
//此处如果不自定义拷贝构造函数的话,
//指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。
//这样delete第一个buf或者析构掉了,第二个对象的指针就成为野指针,
A obj2 = obj1;
delete obj1.pBuf;
printf("%d",obj2.a);
printf("%s",obj2.pBuf);
getchar();
return 0;
}
4. 深拷贝与浅拷贝
深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。 当用一个已经初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用,如果你没有自定义拷贝构造函数的时候,系统将会提供给一个默认的拷贝构造函数来完成这个过程。