复制构造函数
- 只有一个参数,即对同类对象的引用
- 形如 X::X(X& )或X::X(const X& ),二者选一,后者能以常量对象作为参数
- 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
注意:复制构造函数与无参构造函数是不一样的!!无参构造函数不一定存在,复制构造函数一定存在。
class Cpmplex
{
private:
double real,imag;
};
Complex c1;//调用缺省无参构造函数
Cpmplex c2(c1);//调用缺省的复制构造函数,将c2初始化和c1一样。
如果自己定义了复制构造函数,则默认的复制构造函数不存在。
class Complex
{
public:
double real,imag;
Complex(){}
Complex(const Complex& c)
{
real=c.real;
imag=c.imag;
cout<<"Copy Constructor called";
}
};
Complex c1;
Complex c2(c1);//调用自定义的复制构造函数,输出Copy Constructor called
复制构造函数起作用的三种情况
(1)当用一个对象去初始化同类的另一个对象时。
Complex c2(c1);
Complex c2=c1;//初始化语句,与以上语句等价。非赋值语句
(2)如果某函数有一个参数是类A的对象,那么改函数被调用时,类A的复制构造函数将被调用。
class A
{
public:
A(){};
A(A& a)
{
cout<<"Copy constructor called"<<endl;
}
};
void Func(A a1){}
int main()
{
A a2;//创建对象,调用无参构造函数
Func(a2);//调用类A对象的复制构造函数,输出Copy constructor called
//以上自定义类A的复制构造函数,并没有对进行一个复制操作。
//所以在Func(a2)时,形参不一定是实参的拷贝
return 0;
}
(3)如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用。
class A
{
public:
int v;
A(int n){v=n;};
A(const A& a){
v=a.v;
cout<<"Copy constructor called";
}
};
A Func()
{
A b(4);//将对象b的全局变量v初始化为4
return b;//将对象b作为返回值时,调用对象b所属的类的复制构造函数,该函数被调用时输出Copy constructor called
}
int main()
{
cout<<Func().v<<endl;//输出Copy constructor called
//输出 4
return 0;
}
注意:对象间的赋值并不导致复制构造函数被调用
class CMyclass
{
public:
int n;
CMyclass(){};
CMyclass(CMyclass & c){n=2*c.n;}
};
int main()
{
CMyclass c1,c2;
c1.n=9;
c2=c1;//对象间的赋值,不调用复制构造函数
CMyclass c3(c1);//调用复制构造函数
CMyclass c4=c1;//用c1初始化c4,调用复制构造函数
cout<<"c2.n="<<c2.n<<",";//输出c2.n=9,
cout<<"c3.n="<<c3.n<<endl;//输出c3.n=18
return 0;
}
常量引用参数的使用
void fun(CMyclass obj_)
{
cout<<"fun"<<endl;
}
(1)这样的函数,调用时生成形参会引发复制构造函数的调用,开销较大。
(2)可以考虑使用CMyclass& 引用类型作为参数
(3)如果希望确保实参的值在函数中不应被改变,那么可以加const关键字
void fun(CMyclass & obj)
{
//将对象的引用作为形参,形参的变化同时使实参变化,需谨慎修改形参的值!!
}
//为了保证实参不被修改,在形参前加const关键字,就能够确保形参的改变不修改实参
void fun(const CMyclass & obj)
{
//函数中任何试图改变obj值的语句都将变成非法!!
}