我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数、析构函数、复制构造函数和重载赋值操作;即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数。例如以下类:
 
   class CTest
 
   {
 
   public:
 
   CTest();
 
   ~CTest();
 
   CTest(const CTest &);
 
   void operator=(const CTest &);
 
   };
 
   对于构造函数和析构函数不是今天总结的重点,今天的重点是复制构造函数和重载赋值操作。类的复制构造函数原型如下:
 
   class_name(const class_name &src);
 
   一般来说,如果我们没有编写复制构造函数,那么编译器会自动地替每一个类创建一个复制构造函数(也叫隐式复制构造函数);相反的,如果我们编写了一个复制构造函数(显式的复制构造函数),那么编译器就不会创建它。
 
   类的重载赋值操作符的原型如下:
 
   void operator=(const class_name &);
 
   重载赋值操作符是一个特别的赋值运算符,通常是用来把已存在的对象指定给其它相同类型的对象。它是一个特别的成员函数,如果我们没有定义这个成员函数,那么编译器会自动地产生这个成员函数。编译器产生的代码是以单一成员进行对象复制的动作 www.lefeng123.com
 
   总结了复制构造函数和重载赋值操作符的定义,只是让我们了解了它们,而没有真正的深入它们。接下来,再仔细的总结一下它们的调用时机。关于它们的调用时机,我一直都没有真正的明白过,所以这里一定要好好的总结明白了。
 
   复制构造函数和重载赋值操作符的调用时机
 
   对复制构造函数和重载赋值操作符的调用总是发生在不经意间,它们不是经过我们显式的去调用就被执行了。对于这种隐式调用的地方一定要多注意了,这也一般是有陷阱的地方。现在我就用实际的例子来进行验证;例子如下:
 
   #include <iostream>
 
   using namespace std;
 
   class CTest
 
   {
 
   public:
 
   CTest(){}
 
   ~CTest(){}
 
   CTest(const CTest &test)
 
   {
 
   cout《"copy constructor."《endl;
 
   }
 
   void operator=(const CTest &test)
 
   {
 
   cout《"operator="《endl;
 
   }
 
   void Test(CTest test)
 
   {}
 
   CTest Test2()
 
   {
 
   CTest a;
 
   return a;
 
   }
 
   void Test3(CTest &test)
 
   {}
 
   CTest &Test4()
 
   {
 
   CTest *pA = new CTest;
 
   return *pA;
 
   }
 
   };
 
   int main()
 
   {
 
   CTest obj;
 
   CTest obj1(obj); // 调用复制构造函数
 
   obj1 = obj; // 调用重载赋值操作符
 
   /* 传参的过程中,要调用一次复制构造函数
 
   * obj1入栈时会调用复制构造函数创建一个临时对象,与函数内的局部变量具有相同的作用域
 
   */
 
   obj.Test(obj1);
 
   /* 函数返回值时,调用复制构造函数;将返回值赋值给obj2时,调用重载赋值操作符
 
   * 函数返回值时,也会构造一个临时对象;调用复制构造函数将返回值复制到临时对象上
 
   */
 
   CTest obj2;
 
   obj2 = obj.Test2();
 
   obj2.Test3(obj); // 参数是引用,没有调用复制构造函数
 
   CTest obj3;
 
   obj2.Test4(); // 返回值是引用,没有调用复制构造函数
 
   return 0;
 
   }
 
   在代码中都加入了注释,这里就不再做详细的说明了。再次总结一下,如果对象在声明的同时将另一个已存在的对象赋给它,就会调用复制构造函数;如果对象已经存在了,然后再将另一个已存在的对象赋给它,调用的就是重载赋值运算符了。这条规则很适用,希望大家能记住。
 
   复制构造函数和重载赋值操作符的实现要点
 
   在一般的情况下,编译器给我们生成的默认的复制构造函数和重载赋值操作符就已经够用了;但是在一些特别的时候,需要我们手动去实现自己的复制构造函数。
 
   我们都知道,默认的复制构造函数和赋值运算符进行的都是"shallow copy",只是简单地复制字段,因此如果对象中含有动态分配的内存,就需要我们自己重写复制构造函数或者重载赋值运算符来实现"deep copy",确保数据的完整性和安全性。这也就是大家常常说的深拷贝与浅拷贝的问题。下面我就提供一个比较简单的例子来说明一下 www.tfjy386.com
 
   #include <iostream>
 
   using namespace std;
 
   const int MAXSIZE = 260;
 
   class CTest
 
   {
 
   public:
 
   CTest(wchar_t *pInitValue)
 
   {
 
   // Here, I malloc the memory
 
   pValue = new wchar_t[MAXSIZE];
 
   memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
 
   wcscpy_s(pValue, MAXSIZE, pInitValue);
 
   }
 
   ~CTest()
 
   {
 
   if (pValue)
 
   {
 
   delete pValue;
 
   pValue = NULL;
 
   }
 
   }
 
   CTest(const CTest &test)
 
   {
 
   // Malloc the new memory for the pValue
 
   pValue = new wchar_t[MAXSIZE];
 
   memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
 
   wcscpy_s(pValue, MAXSIZE, test.pValue);
 
   }
 
   CTest *operator=(const CTest &test)
 
   {
 
   // This is very important, please remember
 
   if (this == &test)
 
   {
 
   return this;
 
   }
 
   // Please delete the memory, this maybe cause the memory leak
 
   if (pValue)
 
   {
 
   delete pValue;
 
   }
 
   // Malloc the new memory for the pValue
 
   pValue = new wchar_t[MAXSIZE];
 
   memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
 
   wcscpy_s(pValue, MAXSIZE, test.pValue);
 
   return this;
 
   }
 
   void Print()
 
   {
 
   wcout《pValue《endl;
 
   }
 
   private:
 
   wchar_t *pValue; // The pointer points the memory
 
   };
 
   int main()
 
   {
 
   CTest obj(L"obj");
 
   obj.Print();
 
   CTest obj2(L"obj2");
 
   obj2.Print();
 
   obj2 = obj;
 
   obj2.Print();
 
   obj2 = obj2;
 
   obj2.Print();
 
   return 0;
 
   }
 
   特别是在实现重载赋值构造函数时需要多多的注意,在代码中我也添加了注释,大家可以认真的阅读一下代码,然后就懂了,如果不懂的就可以留言问我;当然了,如果我哪里理解错了,也希望大家能给我提出,我们共同进步。
 
   复制构造函数的一些细节
 
   1.以下哪些是复制构造函数
 
   X::X(const X&);
 
   X::X(X);
 
   X::X(X&, int a=1);
 
   X::X(X&, int a=1, int b=2);
 
   这些细节问题在这里也说一说,我也是从别人的博客里看到的,这里自己也总结一下。对于一个类X, 如果一个构造函数的第一个参数是下列之一:
 
   a) X&
 
   b) const X&
 
   c) volatile X&
 
   d) const volatile X&
 
   且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数。
 
   X::X(const X&); //是拷贝构造函数
 
   X::X(X&, int=1); //是拷贝构造函数
 
   X::X(X&, int a=1, int b=2); //当然也是拷贝构造函数
 
   2.类中可以存在超过一个拷贝构造函数
 
   class X {
 
   public:
 
   X(const X&); // const 的拷贝构造
 
   X(X&); // 非const的拷贝构造
 
   };
 
   注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化。如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择哪一个。在我的Visual Studio 2012中,当定义了多个复制构造函数以后,编译器就会有warning,但是程序还能正确运行。

C++中复制构造函数与重载赋值操作符的更多相关文章

  1. C++中复制构造函数与重载赋值操作符总结

    前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符 ...

  2. C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)

    在C++中,有三大函数复制控制(复制构造函数,赋值操作符,析构函数),而在C++11中,加入了移动构造函数,移动赋值操作符.我就斗胆将他们命名为六大函数好了. 一.构造函数 c++primer中说过: ...

  3. C++ 之 重载赋值操作符

    Widget 类中,定义了一个 Bitmap 类型的私有数据成员 -- pb 指针 class Bitmap { ... }; class Widget { private: Bitmap *pb; ...

  4. 5.5 C++重载赋值操作符

    参考:http://www.weixueyuan.net/view/6383.html 总结: 重载赋值操作符同重载类的是拷贝构造函数的原因是一样,将一个对象拷贝给另一个对象,同时当类中存在指针类型的 ...

  5. C++重载赋值操作符

    1.C++中重载赋值操作函数应该返回什么? 类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如 int x,y,z; x=y=z=15; 赋值行为相当 ...

  6. Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)

    问题聚焦: 这个准则比较简短,但是往往就是这种细节的地方,可以提高你的代码质量. 细节决定成败,让我们一起学习这条重载赋值操作符时需要遵守的准则吧. 还是以一个例子开始: Demo // 连锁赋值 x ...

  7. C++中复制构造函数和赋值操作符

    先看一个例子: 定义了一个类:

  8. C++中复制构造函数

    复制构造函数 复制构造函数用于: 根据另一个同类型的对象显示或隐式初始化一个对象 复制一个对象,将它作为实参传给一个函数 从函数返回时复制一个对象 初始化顺序容器中的元素 根据元素初始化式列表初始化数 ...

  9. Java中的构造函数和重载

    一.Java中的构造函数 构造函数是对象被创建时初始化对象的成员方法,它具有和它所在的类完全一样的名字.构造函数只能有入口参数,没有返回类型,因为一个类的构造方法的返回类就是类本身.构造函数定义后,创 ...

随机推荐

  1. 14.1.3 检查InnoDB 可用性:

    14.1.3 Checking InnoDB Availability 14.1.3 检查InnoDB 可用性: 确定是否你的server 支持InnoDB: 1.执行命令 SHOW ENGINES; ...

  2. Win7无法访问NAS或Samba服务器解决之道 转

    Win7无法访问NAS或Samba服务器解决之道 http://www.sina.com.cn  2010年05月12日 01:41  IT168.com [IT168 应用]默认情况下,Window ...

  3. HDOJ 2092 整数解(2次方程整数解公式)

    Problem Description 有二个整数,它们加起来等于某个整数,乘起来又等于另一个整数,它们到底是真还是假,也就是这种整数到底存不存在,实在有点吃不准,你能快速回答吗?看来只能通过编程. ...

  4. [Java] Collections - 源代码学习笔记

    Collection interface 集合接口 1. 在 Collections 体系中,接口 Collection 是根接口 2. 是指一组对象,这些对象被称为 Collection 的元素. ...

  5. POJ-1200(哈希)

    2015-08-19 题意:给出两个数n,nc,并给出一个由nc种字符组成的字符串.求这个字符串中长度为n的子串有多少种. 分析: 1.这个题不用匹配,因为不高效. 2.将长度为n的子串看作n位的nc ...

  6. Promise in AngularJS

    What's promise Angular’s event system provides a lot of power to our Angular apps. One of the most p ...

  7. Android ExpandableListView BaseExpandableListAdapter (类似QQ分组列表)

    分组列表视图(ExpandableListView) 和ListView不同的是它是一个两级的滚动列表视图,每一个组可以展开,显示一些子项,类似于QQ列表,这些项目来至于ExpandableListA ...

  8. linux经常使用命令

    linux经常使用命令 pwd 查看当前工作文件夹的绝对路径 cat input.txt 查看input.txt文件的内容 ls 显示当前文件夹下全部的文件及子文件夹 rm recommender-d ...

  9. Unity3D Asset stored 已下载的位置

    Unity3D Asset stored下载资源在本地的什么目录里呢?C:\Users\accountName\AppData\Roaming\Unity\Asset Store

  10. 彻底卸载MYSQL,windows版

    转自:http://blog.csdn.net/jasonandwho/article/details/7451310 网上搜的总结帖,直接贴过来的... 由于安装MySQL的时候,疏忽没有选择底层编 ...