拷贝构造函数

拷贝构造函数(复制构造函数),一种特殊的构造函数,由编译器调用完成一些基于同一类的其他对象的构建及初始化。其唯一形参必须是引用,但不限制为const,一般会加上const限制。

 调用拷贝构造函数情形:

  1. 一个对象作为函数参数,以值传递的方式传入函数体;
  2. 一个对象作为函数返回值,以值传递的方式从函数返回;
  3. 一个对象用于给另外一个对象进行初始化(赋值初始化);

事实上,拷贝构造函数是由普通构造函数和赋值操作符共同实现的。

通常,

  1. 对于凡是包含动态分配成员或包含指针成员的类都应该提供拷贝构造函数;
  2. 在提供拷贝构造函数的同时,应该考虑重载“=”赋值操作符。

 

1 class A
 2 {
 3         int i;
 4     public:
 5         A(int x):i(x){};        //构造函数
 6         A(const A& b)        //拷贝构造函数
 7         {
 8             i=b.i;
 9         }
10         void show()
11         {
12             cout<<i<<endl;
13         }
14 };
15 int main()
16 {
17     A a(100);
18     A b=a;
19     b.show();
20     return 0;
21 }

结果为:100

可见,拷贝构造函数是一种特殊构造函数,函数名必须和类名一致,唯一的一个参数为类的引用。

 

1. 对象以传值的方式传入函数参数

 

class CExample 
{
private:
 int a;

public:
 //构造函数
 CExample(int b)
 { 
  a = b;
  cout<<"creat: "<<a<<endl;
 }

 //拷贝构造
 CExample(const CExample& C)
 {
  a = C.a;
  cout<<"copy"<<endl;
 }
 
 //析构函数
 ~CExample()
 {
  cout<< "delete: "<<a<<endl;
 }

     void Show ()
 {
         cout<<a<<endl;
     }
};

//全局函数,传入的是对象
void g_Fun(CExample C)
{
 cout<<"test"<<endl;
}

int main()
{
 CExample test(1);
 //传入对象
 g_Fun(test);

 return 0;
}

结果:

creat:1

copy

test

delete:1

delete:1

调用机制:

test对象传入形参时,会先产生一个临时变量;然后调用拷贝构造函数把test的值给临时变量;等g_fun()执行完后,析构掉临时对象。

 

2. 对象以值传递的方式从函数返回

 

#include<iostream>
using namespace std;
class CExample
{
private:
    int a;

public:
    //构造函数
    CExample(int b)
    {
        a = b;
        cout << "creat" << endl;
    }

    //拷贝构造
    CExample(const CExample& C)
    {
        a = C.a;
        cout << "copy" << endl;
    }

    void Show()
    {
        cout << a << endl;
    }
};

//全局函数
CExample g_Fun()
{
    CExample temp(0);
    return temp;
}

int main()
{
    g_Fun();
    return 0;
}

结果:

creat

copy

调用机制:

先产生临时变量;然后调用拷贝构造函数把temp的值给临时变量;在函数执行到最后先析构temp局部变量;等g_fun()执行完后再析构临时对象。

3. 对象需要通过另外一个对象进行初始化

 

CExample A(100);
CExample B = A; 
// CExample B(A); 

 

浅拷贝和深拷贝

1、浅拷贝,只对对象中的数据成员进行简单赋值,默认拷贝构造函数执行的就是浅拷贝。

  默认拷贝函数不对静态数据成员进行处理。

  一旦对象存在了动态成员,浅拷贝就会出现问题。

#include<iostream>
using namespace std;
class Rect
{
public:
    Rect()      // 构造函数,p指向堆中分配的一空间
    {
        p = new int(100);
    }
    ~Rect()     // 析构函数,释放动态分配的空间
    {
        if (p != NULL)
        {
            delete p;
        }
    }
private:
    int width;
    int height;
    int *p;     // 一指针成员
};

int main()
{
    Rect rect1;
    Rect rect2(rect1);   // 复制对象
    return 0;
}

出现问题,运行错误。原因在于在进行对象复制时,对于动态分配的内容没有进行正确操作。在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,所以这两个指针指向了堆里的同一个空间。在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次。

2、深拷贝

#include<iostream>
using namespace std;
class Rect
{
public:
    Rect()      // 构造函数,p指向堆中分配的一空间
    {
        p = new int(100);
    }
    Rect(const Rect& r)
    {
        width = r.width;
        height = r.height;
        p = new int;    // 为新对象重新动态分配空间
        *p = *(r.p);
    }
    ~Rect()     // 析构函数,释放动态分配的空间
    {
        if (p != NULL)
        {
            delete p;
        }
    }
private:
    int width;
    int height;
    int *p;     // 一指针成员
};

int main()
{
    Rect rect1;
    Rect rect2(rect1);   // 复制对象
    return 0;
}

rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容。

 
posted @ 2016-05-29 22:53  chris_chan1024  阅读(191)  评论(0编辑  收藏  举报