拷贝构造函数

时间:2022-12-03 15:55:23
1. 拷贝构造函数的定义

首先举个例子:
  1. class Base
  2. {
  3. public:
  4.        Base();
  5.        Base(Base& obj);                             //1
  6.        Base(const Base& obj);                  //2
  7.        Base(Base& obj, int x);                    //3
  8.        Base(Base& obj, int x=0, int y=0);  //4
  9.        Base& operator=(Base& obj);
  10. protected:
  11.        int  i;
  12. private:
  13. };
复制代码
其中构造函数1,2,3,4哪个是拷贝构造函数,哪个不是?

要回答这个问题,需要先了解一下拷贝构造函数的定义:

拷贝构造函数是一种特殊的成员函数。该函数的功能是用一个已有的对象的值来初始化一个新构造的对象。拷贝构造函数实际上也是构造函数,它是在初始化时被调用来将一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象。

拷贝构造函数的定义格式为:
  1. < 类名 >::< 拷贝构造函数名 >(const < 类名 >& < 引用名 >)
复制代码
其中 < 拷贝构造函数名 > 与类名相同。形参是一个该类的引用,且只能有一个形参。

2.  拷贝构造函数的形式

对于一个类class Base, 如果一个构造函数的第一个参数是下列之一:
(1)    Base::Base(Base& obj)
(2)    Base::Base(const Base& obj)
(3)    Base::Base(volatile Base& obj)
(4)    Base::Base(const volatile Base& obj)

同时,函数没有其他参数;或者,其他参数都有默认值。那么这个函数就是拷贝构造函数。

3. 拷贝构造函数的行为

(1) 默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.
(2) 拷贝构造函数对类中每一个数据成员递归地执行成员拷贝(memberwise Copy)的动作.
        (a) 如果数据成员为某一个类的对象, 那么调用此类的拷贝构造函数.
        (b) 如果数据成员是一个数组, 对数组的每一个执行按位拷贝.
        (c) 如果数据成员是一个数量, 如int,double,那么调用系统内建的赋值运算符对其进行赋值.

4. 拷贝构造函数的使用

(1) 用一个已知对象的值去初始化另一个对象
  1. Base oA;
  2. Base oB(oA);         //拷贝构造函数
  3. Base oC = oA;        //拷贝构造函数
  4. Base oD;
  5. oD = oA;               // operator=
复制代码
(2) 对象作为函数的参数传递时,把实参对象的值传给形参对象。
例如下面的函数
  1. void function(Base obj);
  2. void function(const Base obj);
复制代码
但是如果函数参数是引用类型,那么则不会调用拷贝构造函数。原因很简单,因为实参和形参都是同一个对象,没有发生对象的初始化。例如:
  1. void function(Base& obj);            //不会调用拷贝构造函数
  2. void function(const Base& obj);    //不会调用拷贝构造函数
复制代码
(3) 当对象作为函数的返回值时,编译器会自动创建一个临时的类对象,调用拷贝构造函数对其进行复制,然后将对象返回。
例如:
  1. Base function()
  2. {
  3. Base* pObj = new Base;

  4. return *pObj;
  5. }
复制代码
和第(2)点相同,如果返回值是引用,也不好调用拷贝构造函数
  1. Base& function()
  2. {
  3. Base* pObj = new Base;

  4. return *p;      ////不会调用拷贝构造函数
  5. }
复制代码
5. 深拷贝和浅拷贝

拷贝和浅拷贝的定义可以理解为:

深拷贝:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,
浅拷贝:如果对象存在资源但复制过程并未复制资源的情况视为浅拷贝。

6. 拷贝构造函数与operator=

默认的赋值运算的行为:首先调用父类的赋值运算。然后会为自己独有的各成员寻找赋值运算。如果成员的赋值运算符被重写,则调用这个重写的赋值运算符函数,如果这个重写的运算符函数是private,编译将无法通过。

默认的拷贝构造函数的行为:首先调用父类的拷贝构造函数。