(用旧对象去构造新对象)
拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构造及初始化。
参数的类型:
值类型(不行,会产生递归);
指针类型(能实现要求,但会出现歧义(感觉a的地址给b构造));
引用类型(本类对象的const引用)。
其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。
此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。
同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制或称拷贝是完全可行的。 这个拷贝过程只需要拷贝数据成员,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类 的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数(Copy Constructor)。
拷贝构造函数的参数一一采用引用。如果把一个真实的类对象作为参数传递到拷贝构造函数,会引起无穷递归 。
在类中如果没有显式给出拷贝构造函数时,则C++编译器自动给出一个缺省的拷贝构造函数。
如果有程序设计者定义的构造函数(包括拷贝构造函数),则按函数重载的规律,调用合适的构造函数。
缺省的拷贝构造函数的特点:按位拷贝。
在C++中,下面三种对象需要调用拷贝构造函数(有时也称"复制构造函数"):
1) 一个对象作为函数参数,以值传递的方式传入函数体;(函数传参,类类型的值传递)
class Complex
{
};
void Fun(Complex c1)
{
}
int main()
{
Complex c1(1,2);
Fun(c1);
}
2) 一个对象作为函数返回值,以值传递的方式从函数返回;(函数是类类型的值返回,从局部对象到临时对象的拷贝构造)
Complex Fun()
{
Complex c(10,20);
return c;
}
3) 一个对象用于给另外一个对象进行初始化(常称为赋值初始化);(用已有对象去初始化本类的对象)
int main()
{
Complex c1(1,2);
Complex c2(c1);
Complex c3=c1;
}
当对象的成员变量中存在指针变量时,用存在的对象初始化新建对象时指针变量一同初始化,但这时调用一般拷贝构造函数(浅拷贝)会使新对象中的指针指向和初始化对象指针指向一致,那么当用来初始化的对象在释放内存时会释放掉指针指向的内存,而当新创建的对象释放时会出现程序错误,以为这个指针指向的内存被释放了两次。因此我们需要手动提供另一种拷贝构造函数(深拷贝).
class Complex
{
private:
int Real;
int Image;
public:
//缺省构造
//Complex() {}
//构造函数
Complex(int r=0,int i=0):Real(r),Image(i)
{
}
//拷贝构造函数 不能够定义为const,否则无法对对象成员进行赋值
Complex(const Complex &c):Real(c.Real),Image(c.Image)
{
}
}
int main()
{
Complex c1(1,2);
Complex c2(c1);//c1对象初始化c2
Complex c3=c1;//编译器可自动改写为Complex c3(c1);
}
class CDate
{
int year;
int month;
int day;
public:
//构造函数
CDate(int y=1,int m=1,int d=1):year(y),month(m),day(d)
{
}
//拷贝构造函数
CDate(const CDate &cd):year(cd.year),month(cd.month),day(cd.day)
{
}
};
int main()
{
Cdate data(2022,5,12);
Cdate datb(data);
}
const int len = 20;
class CGoods
{
private
char Name[len];
int Amount;
float Price;
float Total;
public:
// 构造函数
CGoods()
{
memset(Name,0,sizeof(Name));
Amount = 0;
Price = 0.0;
Total = 0.0;
}
CGoods(const char *name,int amount,int price)
{
strcpy_s(Name,len,name);
Amount = amount;
Price= price;
Total = Amount * Price;
}
//拷贝构造函数
CGoods(const CGoos &cg):Amount(cg.Amount),Price(cg.Price),Total(cg.Total)
{
strcpy_s(Name,len,cg.Nmae);
}
};
int main()
{
CGoods c1("wer",12,1235);
CGoods c2(c1);
}
当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出(Stack Overflow)。除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。