zoukankan      html  css  js  c++  java
  • 23、【C++基础】拷贝构造函数和重载赋值运算符

    函数原型

    在C++中建立一个类,这个类中肯定会包括构造函数、析构函数、拷贝构造函数和重载赋值操作。

    拷贝构造函数是一种特殊的构造函数,其作用也是为类的成员初始化以及为对象的构造分配存储空间。函数的名称必须和类名称一致,无返回类型,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变。

    拷贝构造函数原型如下:

    1 class_name(const class_name &src);

    对于一个类X, 如果一个构造函数的第一个参数是下列之一:

    1   & X;
    2   const & X;
    3   volatile & X;
    4   const volatile & X;

    且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数,如下:

    1 X::X(const & X);   
    2 X::X(& X, int=1); 
    3 X::X(& X, int a=1, int b=2); 

    重载赋值操作符是一个特别的赋值运算符,通常是用来把已存在的对象赋值给其它相同类型的对象。

    重载赋值操作符的原型如下:

    1 class_name& operator=(const class_name &src);

    拷贝构造函数与重载赋值操作符的调用

    当类的对象需要拷贝时,复制构造函数将会被调用。以下情况都会调用复制构造函数:
      一个对象以值传递的方式传入函数体;
      一个对象以值传递的方式从函数返回;
      一个对象需要通过另外一个对象进行初始化。

    如果对象在声明的同时将另一个已存在的对象赋给它,就会调用复制构造函数;如果对象已经存在了,然后再将另一个已存在的对象赋给它,调用的就是重载赋值运算符。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class CTest
     5 {
     6 public:
     7      CTest(){}
     8      ~CTest(){}
     9 
    10      CTest(const CTest &test)
    11      {
    12           cout<<"copy constructor."<<endl;
    13      }
    14 
    15      void operator=(const CTest &test)
    16      {
    17           cout<<"operator="<<endl;
    18      }
    19 
    20      void Test(CTest test)
    21      {}
    22 
    23      CTest Test2()
    24      {
    25           CTest a;
    26           return a;
    27      }
    28 
    29      void Test3(CTest &test)
    30      {}
    31 
    32      CTest &Test4()
    33      {
    34           CTest *pA = new CTest;
    35           return *pA;
    36      }
    37 };
    38 
    39 int main()
    40 {
    41      CTest obj;
    42 
    43      CTest obj1(obj); // 调用复制构造函数
    44 
    45      obj1 = obj; // 调用重载赋值操作符
    46 
    47      /* 传参的过程中,要调用一次复制构造函数
    48      * obj1入栈时会调用复制构造函数创建一个临时对象,与函数内的局部变量具有相同的作用域
    49      */
    50      obj.Test(obj1);
    51 
    52      /* 函数返回值时,调用复制构造函数;将返回值赋值给obj2时,调用重载赋值操作符
    53      * 函数返回值时,也会构造一个临时对象;调用复制构造函数将返回值复制到临时对象上
    54      */
    55      CTest obj2;
    56      obj2 = obj.Test2();
    57 
    58      obj2.Test3(obj); // 参数是引用,没有调用复制构造函数
    59 
    60      CTest obj3;
    61      obj2.Test4(); // 返回值是引用,没有调用复制构造函数
    62 
    63      return 0;
    64 }

    深拷贝(deep copy)与浅拷贝(shallow copy)

    如果在类中没有显式地声明,那么编译器会自动生成默认的复制构造函数和重载赋值操作符。默认的复制构造函数和赋值运算符进行的都是“shallow copy”,只是简单地复制字段,把值一一赋给要拷贝的值。因此如果对象中含有动态分配的内存,就需要我们自己重写复制构造函数和重载赋值操作符来实现“deep copy”,确保数据的完整性和安全性。

    例如:类内成员变量需要动态开辟堆内存,如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

    深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,资源重新分配,使对象拥有不同的资源,但资源的内容是一样的,这个过程就是深拷贝;反之,没有重新分配资源,两个对象就有用共同的资源,同时对资源可以访问,就是浅拷贝。浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

     1 #include <iostream>
     2 using namespace std;
     3 class CA
     4 {
     5  public:
     6   CA(int b,char* cstr)
     7   {
     8    a=b;
     9    str=new char[b];
    10    strcpy(str,cstr);
    11   }
    12   CA(const CA& C)
    13   {
    14    a=C.a;
    15    str=new char[a]; //深拷贝
    16    if(str!=0)
    17     strcpy(str,C.str);
    18   }
    19   void Show()
    20   {
    21    cout<<str<<endl;
    22   }
    23   ~CA()
    24   {
    25    delete str;
    26   }
    27  private:
    28   int a;
    29   char *str;
    30 };
    31 
    32 int main()
    33 {
    34  CA A(10,"Hello!");
    35  CA B=A;
    36  B.Show();
    37  return 0;
    38 } 

    三法则(英语:rule of three,the Law of The Big Three,The Big Three;三法则,三大定律)在 C++ 程序设计里,它是一个以设计的基本原则而制定的定律,三法则的要求在于,假如类型有明显地定义下列其中一个成员函数,那么程序员必须连其他二个成员函数也一同编写至类型内,亦即下列三个成员函数缺一不可:

    • 析构函数(Destructor)
    • 复制构造函数(copy constructor)
    • 复制赋值运算符(copy assignment operator)
  • 相关阅读:
    快速入门 ASP.NET MVC
    关于ASP.NET中由于无法创建应用程序域,因此未能执行请求解决方案
    Microsoft ASP.NET MVC Beta IIS6 部署
    弹窗显示正在执行的任务
    多线程加深理解_进攻五个城
    反射与配置文件简单使用
    C#中MemberwiseClone的理解
    C# App.config 自定义 配置节 报错“配置系统未能初始化” 解决方法
    多线程信号源的理解
    日志的记录
  • 原文地址:https://www.cnblogs.com/Long-w/p/9675893.html
Copyright © 2011-2022 走看看