昨天晚上在看智能指针的时候,我发现自己连一个拷贝构造函数和赋值构造函数都写不出来,自己就尝试写了一个版本,结果发现错误百出,对于拷贝构造函数和赋值构造函数的理解仅仅停留在理论的方面,而不知其中太多的内涵。

比如我们都知道拷贝构造函数和赋值构造函数最大的不同在于:

拷贝构造是确确实实构造一个新的对象,并给新对象的私有成员赋上参数对象的私有成员的值,新构造的对象和参数对象地址是不一样的,所以如果该类中有一个私有成员是指向堆中某一块内存,如果仅仅对该私有成员进行浅拷贝,那么会出现多个指针指向堆中同一块内存,这是会出现问题,如果那块内存被释放了,就会出现其他指针指向一块被释放的内存,出现未定义的值的问题,如果深拷贝,就不会出现问题,因为深拷贝,不会出现指向堆中同一块内存的问题,因为每一次拷贝,都会开辟新的内存供对象存放其值。

下面是浅拷贝构造函数的代码:

#include <iostream>using namespace std;class A
{
private:int* n;public:A(){n = new int[10];n[0] = 1;cout<<"constructor is called\n";}A(const A& a){n = a.n;cout<<"copy constructor is called\n";}~A(){cout<<"destructor is called\n";delete n;}void get(){cout<<"n[0]: "<<n[0]<<endl;}
};int main()
{A* a = new A();A b = *a;delete a;b.get();return 0;
}

运行结果如下:

下面是深拷贝构造函数的代码:

#include <iostream>
#include <string.h>
using namespace std;class A
{
private:int* n;public:A(){n = new int[10];n[0] = 1;cout<<"constructor is called\n";}A(const A& a){n = new int[10];memcpy(n, a.n, 10);  //通过按字节拷贝,将堆中一块内存存储到另一块内存cout<<"copy constructor is called\n";}~A(){cout<<"destructor is called\n";delete n;}void get(){cout<<"n[0]: "<<n[0]<<endl;}
};int main()
{A* a = new A();A b = *a;delete a;b.get();return 0;
}

运行截图如下:

但是赋值构造函数是将一个参数对象中私有成员赋给一个已经在内存中占据内存的对象的私有成员,赋值构造函数被赋值的对象必须已经在内存中,否则调用的将是拷贝构造函数,当然赋值构造函数也有深拷贝和浅拷贝的问题。当然赋值构造函数必须能够处理自我赋值的问题,因为自我赋值会出现指针指向一个已经释放的内存。还有赋值构造函数必须注意它的函数原型,参数必须是引用类型,返回值也必须是引用类型,否则在传参和返回的时候都会再次调用一次拷贝构造函数。

#include <iostream>
#include <string.h>
using namespace std;class A
{
private:int* n;public:A(){n = new int[10];n[0] = 1;cout<<"constructor is called\n";}A(const A& a) //拷贝构造函数的参数一定是引用,不能不是引用,不然会出现无限递归
    {n = new int[10];memcpy(n, a.n, 10);  //通过按字节拷贝,将堆中一块内存存储到另一块内存cout<<"copy constructor is called\n";}A& operator=(const A& a)  //记住形参和返回值一定要是引用类型,否则传参和返回时会自动调用拷贝构造函数{if(this == &a)     //为什么需要进行自我赋值判断呢?因为下面要进行释放n的操作,如果是自我赋值,而没有进行判断的话,那么就会出现讲一个释放了的内存赋给一个指针return *this;if(n != NULL){delete n;n == NULL;   //记住释放完内存将指针赋为NULL}n = new int[10];memcpy(n, a.n, 10);cout<<"assign constructor is called\n";return *this;}~A(){cout<<"destructor is called\n";delete n;     n = NULL;  //记住释放完内存将指针赋为NULL}void get(){cout<<"n[0]: "<<n[0]<<endl;}
};int main()
{A* a = new A();A* b =  new A();*b = *a;delete a;b->get();
return 0;
}

运行截图如下:

如果我们在赋值构造函数的形参和返回值不用引用类型,代码如下:

#include <iostream>
#include <string.h>
using namespace std;class A
{
private:int* n;public:A(){n = new int[10];n[0] = 1;cout<<"constructor is called\n";}A(const A& a) //拷贝构造函数的参数一定是引用,不能不是引用,不然会出现无限递归
    {n = new int[10];memcpy(n, a.n, 10);  //通过按字节拷贝,将堆中一块内存存储到另一块内存cout<<"copy constructor is called\n";}A operator=(const A a)   //传参和返回值设置错误{if(this == &a)return *this;if(n != NULL){delete n;n == NULL;}n = new int[10];memcpy(n, a.n, 10);cout<<"assign constructor is called\n";return *this;}~A(){cout<<"destructor is called\n";delete n;}void get(){cout<<"n[0]: "<<n[0]<<endl;}
};int main()
{A* a = new A();A* b =  new A();*b = *a;delete a;b->get();while(1){}return 0;
}

运行截图如下:

多了两次的拷贝构造函数的调用和两次析构函数的调用。

转载于:https://www.cnblogs.com/GODYCA/archive/2013/01/16/2862885.html

对于拷贝构造函数和赋值构造函数的理解相关推荐

  1. 不存在从void转换到sqlist的适当构造函数_拷贝构造函数与赋值构造函数

    拷贝构造函数与赋值构造函数 在C++中,如果要创建一个新的类,并用已有的类来给它附初值.就要用到拷贝构造函数,拷贝构造函数又分为两种. 1.合成的拷贝构造函数 在你没有定义自己的拷贝构造函数而又调用了 ...

  2. C++ 拷贝构造函数和赋值构造函数

    在C++中复制控制是一个比较重要的话题,主要包括复制构造函数.重载赋值操作符.析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的 ...

  3. C++---拷贝构造函数和赋值构造函数

    摘要:最近看了一道面试题问:C++ 中拷贝赋值函数的形参能否进行值传递?我知道一般来说,拷贝构造函数的形参必须是自身类型的引用(<面向对象程序设计--C++语言描述(第二版)>这本书中有叙 ...

  4. Cpp 对象模型探索 / 拷贝构造函数 和 赋值构造函数 的调用时机

    class A { public:A() {};A(const A& obj) {}A& operator=(const A& obj) { return *this; } } ...

  5. 拷贝构造函数和赋值构造函数声明为私有的作用

    转贴地址:http://blog.csdn.net/winer632/archive/2009/01/12/3762292.aspx 每个类只有一个赋值函数. 由于并非所有的对象都会使用拷贝构造函数和 ...

  6. 网易游戏笔试题:编写string类的构造函数、拷贝构造函数、赋值构造函数和析构函数

    题目: class MyString { public: MyString(const char *str);//构造函数 MyString(const MyString& strClass) ...

  7. C++中拷贝构造函数与赋值构造函数详解

    1.  拷贝构造函数 什么时候会调用拷贝构造函数  ?            使用一个已经创建好的对象来初始化一个新的对象. Student mya("zhang3",22);   ...

  8. C/C++中的拷贝构造函数和赋值构造函数

    代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 class A{ 7 pu ...

  9. 构造函数、拷贝构造函数、赋值函数和析构函数

    文章目录 一.构造函数 1.认识构造函数 2.初始化列表 二.拷贝构造函数 1.类对象的拷贝 2.浅拷贝和深拷贝 三.赋值函数 四.析构函数 1.认识析构函数 2.销毁,清理? 3.析构函数来阻止该类 ...

最新文章

  1. html5表单动态添加,js动态添加表单实例
  2. python读取路径中字符串_python实现提取str字符串/json中多级目录下的某个值
  3. spring boot 整合 谷歌guava的EventBus 实现单机版的消息发布订阅
  4. 转:神奇的Fastcgi_Finish_Request
  5. gemm() 与 gesvd() 到矩阵求逆(inverse)(根据 SVD 分解和矩阵乘法求矩阵的逆)
  6. 常用Docker 镜像命令(二)
  7. 一周第二次课(12月12日)
  8. ai决策_基于经验的决策与基于事实的决策:AI / ML如何改变工程师的工作方式
  9. 宁银消费金融来了 母行授信80亿,全国急招人
  10. 系统试运行报告是谁写的_深圳个人信用报告查询系统入口https://ipcrs.pbccrc.org.cn/...
  11. nisp一级练习题及答案
  12. 牛客笔试OJ-在线编辑器输入输出总结
  13. 如何将腾讯QLV格式转换成MP4普通视频
  14. 第十三课、类族的结构进化-------------------狄泰软件学院
  15. 背包问题变种:将数组分成两部分使得两部分的和的差最小
  16. c语言程序设计分值,计算机考试题分值分布
  17. debug - UITextField 输入完跳入下一field,按钮变化
  18. windows中的出站和入站规则
  19. 船舶强度与结构设计大作业二matlab,华科船舶结构强度第二次大作业
  20. 商城系统:包含用户注册/用户登陆/商品浏览/我的购物车功能.

热门文章

  1. C++模拟实现Objective-C协议和代理模式
  2. 在HTML网页中嵌入脚本的方式
  3. Perl 安装 模块Net::SSH2 有些0day是ssh2
  4. jQuery源码解析之position()
  5. 聊聊flink的Execution Plan Visualization
  6. 三个值得期待的JavaScript新功能!
  7. 想了解概率图模型?你要先理解图论的基本定义与形式
  8. [20170412]bbed恢复修改记录(不等长).txt
  9. Myeclipse2013下载,安装,破解,介绍(CSDN首发)
  10. WMI使用的WIN32_类库名