如果一个构造函数的第一个参数是类本身的引用,且没有其它参数(或者其它的参数都有默认值),则该构造函数为拷贝构造函数。
拷贝(复制)构造函数:利用同类对象构造一个新的对象
●1.函数名和类同名 (构造函数)
●2.没有返回值 (构造函数)
●3.第一个参数必须是类本身的对象的const 引用.可以有其它的参数,但其它参数必须有默认值,注意一般都只有一个参数.
●4.不能重载
class Foo
{
public:
Foo(); //默认构造函数
Foo(const Foo &f); //拷贝构造函数
//...
};
拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用,且这个参数几乎总是const的引用。其作用是使用一个已经存在的对象去初始化同类的一个新对象。如果我们不定义这个函数,系统会生成一个默认的拷贝构造函数,它的作用是从给定对象中依次将每个非static成员拷贝到正在创建的新对象中。
如果类没有实现拷贝构造函数,它自动生成一个默认的拷贝构造函数,默认的完成分内的事情(1.为每个成员变量分配内存,2.每个成员变量赋值)
拷贝构造函数的参数采用引用方式。如果是非引用,则调用永远也不会成功:为了调用拷贝构造函数,我们必须复制它的实参,但为了复制实参,我们又需要调用拷贝构造函数,如此无限循环。
拷贝构造函数的特征。
(1)拷贝构造函数的名字与类名相同,并且没有返回值。
(2)拷贝构造函数只有一个参数,或者其它的参数都有默认值。
(3)每个类都有一个拷贝构造函数。如果你没有定义拷贝构造函数,系统会自动生成拷贝构造函数。
调用拷贝构造函数的情况有以下几种。
●显式使用一个对象初始化另一个对象。
●对象作为函数实参传递给一个非引用类型的形参。(只在笔试面试中出现,实际编码要求传引用)
●返回类型为非引用类型的函数返回一个对象。
例如:拷贝构造函数应用。
设计一个复数类,两个数据成员分别表示复数的实部和虚部。定义两个构造函数,一个普通构造函数,一个拷贝构造函数。定义add函数完成两个复数的加法。
class Complex //复数类
{
public:
Complex(double r, double i);
Complex(const Complex& c);
Complex add(Complex c);//加法
private:
double real; //实部
double image; //虚部
};
Complex::Complex(double r, double i) :real(r), image(i)
{
cout << "构造函数,实部:"<<real<<",虚部:"<<image << endl;
}
Complex::Complex(const Complex & c)
{
real = c.real;
image = c.image;
cout << "拷贝构造函数,实部:" << real << ",虚部:" << image << endl;
}
Complex Complex::add(Complex c)
{
Complex y(real + c.real, image + c.image); //构造函数
return y;//返回值为类对象,会调用拷贝构造函数
}
void f(Complex n) //参数是类对象,会调用拷贝构造函数
{
cout << "f(Complex n)" << endl;
}
int main()
{
Complex a(3, 4); //调用构造函数
Complex b(6.5, 7.5);//调用构造函数
Complex c(a); //拷贝构造函数
Complex d = c;//拷贝构造函数,注意和下一节的赋值区分开
f(b); //拷贝构造函数
c = a.add(b); //拷贝构造函数
return 0;
}
程序分析:
1.第33,34行调用构造函数,创建了两个复数类对象a和b。输出第1,第2行
2.第35行,Complex c(a),用一个已知对象初始化另一个对象,系统调用拷贝构造函数,输出第3行。
3.第36行,Complex d = c;利用c初始化对象d,这一句看似=赋值,其实还是调用拷贝构造函数,因为这里还是初始化过程。这两种写法是等价的Complex d=c等同Complex d(c)等同Complex d{c},这种写法对于内置类型也是一样的,int a = 10等同int a(10)等同int a{10}。
4.第38行,f(b),将实参b传给形参n,因为形参是非引用的类对象,调用拷贝构造函数。
5.第39行,c=a.add(b),首先实参b传递给非引用形参c会调用拷贝构造函数,接着在add函数中定义了一个复数类对象y(24行),系统会调用构造函数。
6.最后,函数add的返回值是一个非引用对象,系统会创建一个临时对象,将局部对象y赋值给临时对象,这时也要调用拷贝构造函数。