什么是拷贝构造函数?拷贝构造函数什么时候被调用

1.什么是拷贝构造函数
CA(const CA& C)就是咱们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的惟一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。
当用一个已初始化过了的自定义类类型对象去初始化另外一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象须要拷贝时,拷贝构造函数将会被调用。如下状况都会调用拷贝构造函数:
① 程序中须要新创建一个对象,并用另外一个同类的对象对它初始化,如前面介绍的那样。
② 当函数的参数为类的对象时。在调用函数时须要将实参对象完整地传递给形参,也就是须要创建一个实参的拷贝,这就是按实参复制一个形参,系统是经过调用复制构造函数来实现的,这样能保证形参具备和实参彻底相同的值。
③ 函数的返回值是类的对象。在函数调用完毕将返回值带回函数调用处时。此时须要将函数中的对象复制一个临时对象并传给该函数的调用处。如
Box f( ) //函数f的类型为Box类类型
{Box box1(12,15,18);
return box1; //返回值是Box类的对象
}
int main( )
{Box box2; //定义Box类的对象box2
box2=f( ); //调用f函数,返回Box类的临时对象,并将它赋值给box2
}
若是在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。
  自定义拷贝构造函数是一种良好的编程风格,它能够阻止编译器造成默认的拷贝构造函数,提升源码效率。
浅拷贝和深拷贝
  在某些情况下,类内成员变量须要动态开辟堆内存,若是实行位拷贝,也就是把对象里的值彻底复制给另外一个对象,如A=B。这时,若是B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
  深拷贝和浅拷贝能够简单理解为:若是一个类拥有资源,当这个类的对象发生复制过程的时候,资源从新分配,这个过程就是深拷贝,反之,没有从新分配资源,就是浅拷贝。
2.C++拷贝构造函数的几个细节

1) 如下函数哪一个是拷贝构造函数,为何?
1.X::X( const X&);
2.X::X(X);
3.X::X(X&, int a=1);
4.X::X(X&, int a=1, b=2);
解答:1) 对于一个类X,若是一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其余参数或其余参数都有默认值,那么这个函数是拷贝构造函数.
1.X::X( const X&); //是拷贝构造函数
2.X::X(X&, int =1); //是拷贝构造函数

2) 一个类中能够存在多于一个的拷贝构造函数吗?
解答:类中能够存在超过一个拷贝构造函数,
1.class X {
2.public :
3. X( const X&);
4. X(X&); // OK
5.};
注意,若是一个类中只存在一个参数为X&的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化.
1.class X {
2.public :
3. X();
4. X(X&);
5.};
6.
7.const X cx;
8.X x = cx; // error
若是一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数.
这个默认的参数可能为X::X(const X&)或X::X(X&),由编译器根据上下文决定选择哪个.
默认拷贝构造函数的行为以下:
默认的拷贝构造函数执行的顺序与其余用户定义的构造函数相同,执行先父类后子类的构造.
拷贝构造函数对类中每个数据成员执行成员拷贝(memberwise Copy)的动做.
a)若是数据成员为某一个类的实例,那么调用此类的拷贝构造函数.
b)若是数据成员是一个数组,对数组的每个执行按位拷贝.
c)若是数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.
3) 拷贝构造函数不能由成员函数模版生成.
struct X {
template < typename T>
X( const T& ); // NOT copy ctor, T can't be X
template < typename T>
operator=( const T& ); // NOT copy ass't, T can't be X
};
缘由很简单, 成员函数模版并不改变语言的规则,而语言的规则说,若是程序须要一个拷贝构造函数而你没有声明它,那么编译器会为你自动生成一个.因此成员函数模版并不会阻止编译器生成拷贝构造函数, 赋值运算符重载也遵循一样的规则
3.拷贝构造函数与赋值函数的异同:
1) 拷贝构造,是一个的对象来初始化一片内存区域,这片内存区域就是你的新对象的内存区域赋值运算,对于一个已经被初始化的对象来进行operator=操做
class A;
A a;
A b=a; //拷贝构造函数调用
//或
A b(a); //拷贝构造函数调用
///////////////////////////////////
A a;
A b;
b =a; //赋值运算符调用
你只须要记住,在C++语言里,
String s2(s1);
String s3 = s1;
只是语法形式的不一样,意义是同样的,都是定义加初始化,都调用拷贝构造函数。
2) 通常来讲是在数据成员包含指针对象的时候,应付两种不一样的处理需求的 一种是复制指针对象,一种是引用指针对象 copy大多数状况下是复制,=则是引用对象的
例子:
class A
{
int nLen;
char * pData;
}
显然
A a, b;
a=b的时候,对于pData数据存在两种需求
第一种copy
a.pData = new char [nLen];
memcpy(a.pData, b.pData, nLen);
另一种(引用方式):
a.pData = b.pData

经过对比就能够看到,他们是不一样的
每每把第一种用copy使用,第二种用=实现
你只要记住拷贝构造函数是用于类中指针,对象间的COPY
3) 拷贝构造函数首先是一个构造函数,它调用的时候产生一个对象,是经过参数传进来的那个对象来初始化,产生的对象。
operator=();是把一个对象赋值给一个原有的对象,因此若是原来的对象中有内存分配要先把内存释放掉,并且还要检查一下两个对象是否是同一个对象,若是是的话就不作任何操做。
还要注意的是拷贝构造函数是构造函数,不返回值
而赋值函数须要返回一个对象自身的引用,以便赋值以后的操做
4) 在形式上
类名(形参表列); //普通构造函数的声明,如Box(int h,int w,int len);
类名(类名& 对象名); //复制构造函数的声明,如Box(Box &b);
5) 在创建对象时,实参类型不一样。系统会根据实参的类型决定调用普通构造函数或复制构造函数。如:
Box box1(12,15,16); //实参为整数,调用普通构造函数
Box box2(box1); //实参是对象名,调用复制构造函数编程

拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其余对象的构建及初始化。其惟一的参数(对象的引用)是不可变的(const类型)。此函数常常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。

在C++中,下面三种对象须要调用拷贝构造函数:   数组

1) 一个对象以值传递的方式传入函数体;   函数

2) 一个对象以值传递的方式从函数返回;   指针

3) 一个对象须要经过另一个对象进行初始化;   对象

若是在前两种状况不使用拷贝构造函数的时候,就会致使一个指针指向已经被删除的内存空间。对于第三种状况来讲,初始化和赋值的不一样含义是构造函数调用的缘由。事实上,拷贝构造函数是由普通构造函数和赋值操做符共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有不少。   内存

拷贝构造函数不能够改变它所引用的对象,其缘由以下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。若是一个对象是被传入本身的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才能够传入它本身的拷贝构造函数,这会致使无限循环直至栈溢出(Stack Overflow)。除了当对象传入函数的时候被隐式调用之外,拷贝构造函数在对象被函数返回的时候也一样的被调用。资源

相关文章
相关标签/搜索