c++浅拷贝和深拷贝---14
原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/
1.什么是拷贝构造函数:
2.调用拷贝构造函数的情形:
(1)一个对象以值传递的方式传入函数体
#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test();
test(const test& ctest);
~test();
private:
char Name;
}; test::test()
{
cout <<"Construction "<<endl;
} test::test(const test& ctest)
{
cout <<"Copy Construction "<<endl;
} test::~test()
{
cout <<"Destruction "<<endl;
} void function(test param_test)
{
cout <<"into function"<<endl;
} int main(int argc, char const *argv[])
{
test Atest;
function(Atest); return 0;
}
运行结果

(2)一个对象以值传递的方式从函数返回
#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test();
test(const test& ctest);
~test();
private:
char Name;
}; test::test()
{
cout <<"Construction "<<endl;
} test::test(const test& ctest)
{
cout <<"Copy Construction "<<endl;
} test::~test()
{
cout <<"Destruction "<<endl;
} test function(test param_test)
{
cout <<"into function"<<endl;
return param_test;
} int main(int argc, char const *argv[])
{
test Atest;
function(Atest); return 0;
}
运行结果:

(3)一个对象需要通过另外一个对象进行初始化。
#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test();
test(const test& ctest);
~test();
private:
char Name;
}; test::test()
{
cout <<"Construction "<<endl;
} test::test(const test& ctest)
{
cout <<"Copy Construction "<<endl;
} test::~test()
{
cout <<"Destruction "<<endl;
} int main(int argc, char const *argv[])
{
test Atest;
test Btest = Atest; return 0;
}
运行结果:

3.浅拷贝和深拷贝:
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
---》深拷贝:(查看在堆上分配的内存资源进行深拷贝)

#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test(char* name);
test(const test& ctest);
~test();
void Printf();
private:
char* PName;
}; test::test(char* name)//普通构造函数
{
if(name != NULL)
{
cout <<"Construction "<<name<<endl;
int len = strlen(name)+1;
PName = new char[len]; memset(PName, 0, len);
strcpy(PName,name);
}
else
{
PName = NULL;
}
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
} test::test(const test& ctest)//深拷贝构造函数
{
if(ctest.PName != NULL)
{
cout <<"Copy Construction "<<endl;
int len = strlen(ctest.PName)+1;
PName = new char[len];
memset(PName, 0, len);
strcpy(PName,ctest.PName);
}
else
{
PName = NULL;
}
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
} test::~test()
{
cout <<"Destruction "<<endl;
if(PName != NULL)
{
Printf();
delete []PName;
PName = NULL;
}
} void test::Printf()
{
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
} int main(int argc, char const *argv[])
{
test Atest((char*)"zhouxuewei"); test Btest = Atest;//复制对象的副本,此刻调用拷贝构造函数 return 0;
}
运行结果:

----》浅拷贝(使用编译器默认的拷贝构造函数)
#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test(char* name);
//test(const test& ctest);
~test();
void Printf();
private:
char* PName;
}; test::test(char* name)//普通构造函数
{
if(name != NULL)
{
cout <<"Construction "<<name<<endl;
int len = strlen(name)+;
PName = new char[len]; memset(PName, , len);
strcpy(PName,name);
}
else
{
PName = NULL;
}
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
}
/*
test::test(const test& ctest)//深拷贝构造函数
{
if(ctest.PName != NULL)
{
cout <<"Copy Construction "<<endl;
int len = strlen(ctest.PName)+1;
PName = new char[len];
memset(PName, 0, len);
strcpy(PName,ctest.PName);
}
else
{
PName = NULL;
}
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
}*/ test::~test()
{
cout <<"Destruction "<<endl;
if(PName != NULL)
{
Printf();
delete []PName;
PName = NULL;
}
} void test::Printf()
{
cout <<"&PName = "<<static_cast<void*>(PName)<<endl;
} int main(int argc, char const *argv[])
{
test Atest((char*)"zhouxuewei"); test Btest = Atest;//复制对象的副本,此刻调用拷贝构造函数 return ;
}
运行结果:结果可以看出,拷贝的对象使用的堆内存地址相同,析构时free两次,产生错误:

4.赋值运算符
#include <iostream>
#include <cstring> using namespace std; class test
{
public:
test(char* name,int value);
test(const test& ctest);
~test();
test& operator=(const test& otest);
void Printf();
private:
char* PName;
int value;
static unsigned char count;
}; unsigned char test::count = 0; test::test(char* name,int val)//普通构造函数
{
if(name != NULL)
{
int len = strlen(name)+1;
PName = new char[len]; memset(PName, 0, len);
strcpy(PName,name);
}
else
{
PName = NULL;
}
value = val;
cout <<"&PName = "<<static_cast<void*>(PName)<<", name = "<<PName<<", value = "<<value<<endl;
count++;
} test::test(const test& ctest)//深拷贝构造函数
{
if(ctest.PName != NULL)
{
cout <<"Copy Construction "<<endl;
int len = strlen(ctest.PName)+1;
PName = new char[len];
memset(PName, 0, len);
strcpy(PName,ctest.PName);
}
else
{
PName = NULL;
}
cout <<"&PName = "<<static_cast<void*>(PName)<<", name = "<<PName<<endl;
count++;
} test::~test()
{
cout <<"Destruction "<<", count = "<<static_cast<int>(count)<<endl;
if(PName != NULL)
{
Printf();
delete []PName;
PName = NULL;
}
count--;
} test& test::operator=(const test& otest)
{
cout <<"into operator "<<endl;
if(&otest == this) //自赋值检查
{
return *this;
}
if(PName != NULL)
{
delete []PName; //原有资源的释放
PName = NULL;
}
if(otest.PName != NULL)
{
int len = strlen(otest.PName)+1;//开始赋值
PName = new char[len];
memset(PName, 0, len);
strcpy(PName, otest.PName);
}
else
PName = NULL;
value = otest.value;
return *this;
} void test::Printf()
{
cout <<"&PName = "<<static_cast<void*>(PName)<<",name = "<<PName<<", value = "<<value<<endl;
} int main(int argc, char const *argv[])
{
test Atest((char*)"zhouxuewei",111);
test Btest((char*)"wanghuixi",222); Atest = Btest; return 0;
}
运行结果:

总结:
1》何时需要定义拷贝构造函数:
a.类数据成员有指针。
b.类数据成员管理资源(如打开文件)
2》如果一个类需要析构函数来释放资源,则他需要一个拷贝构造函数。
3》如果想禁止一个类的拷贝构造,则需要将拷贝构造函数声明为private。
c++浅拷贝和深拷贝---14的更多相关文章
- 编写高质量代码改善C#程序的157个建议——建议14: 正确实现浅拷贝和深拷贝
建议14: 正确实现浅拷贝和深拷贝 为对象创建副本的技术称为拷贝(也叫克隆).我们将拷贝分为浅拷贝和深拷贝. 浅拷贝 将对象中的所有字段复制到新的对象(副本)中.其中,值类型字段的值被复制到副本中后, ...
- 编写高质量代码改善C#程序的157个建议[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]
前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深 ...
- 浅析JavaScript解析赋值、浅拷贝和深拷贝的区别
文章首发于sau交流学习社区 一.赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为: 1.基本数据类型:赋值,赋值之后两个变量互不影响 2.引用数据类型:赋**址**,两个变量具有相同 ...
- js对象浅拷贝和深拷贝详解
js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...
- C#程序编写高质量代码改善的157个建议【13-15】[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]
前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深 ...
- java中的浅拷贝和深拷贝
复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...
- [转] js对象浅拷贝和深拷贝详解
本文为大家分享了JavaScript对象的浅拷贝和深拷贝代码,供大家参考,具体内容如下 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: var Chinese = ...
- 【转】Python中的赋值、浅拷贝、深拷贝介绍
这篇文章主要介绍了Python中的赋值.浅拷贝.深拷贝介绍,Python中也分为简单赋值.浅拷贝.深拷贝这几种"拷贝"方式,需要的朋友可以参考下 和很多语言一样,Python中 ...
- 渐析java的浅拷贝和深拷贝
首先来看看浅拷贝和深拷贝的定义: 浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝. 深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所 ...
随机推荐
- 如何在CentOS 6.5上升级PHP
CentOS 6.5上默认安装PHP 5.3.因为后台网站无法正确运行在PHP 5.3上,所以计划将PHP升级到开发平台一样的版本PHP 5.5.为了方便,我们采用YUM的方式升级PHP 工具/原料 ...
- Redis的内存回收机制
Redis的内存回收机制 2018年01月16日 17:11:48 chs007chs 阅读数:1172 Redis的内存回收机制主要体现在一下两个方面: 删除过期时间的键对象 删除过期键对象 : ...
- Ubuntu free以及Linux内存占用大的解释
-bash-3.00$ free total used free shared buffers cached Mem: 514020 465932 48088 0 15864 348844 -/ bu ...
- JVM调优总结(一):基本概念
一.数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型. 基本类型的变量保存原始值,即:他代表的值就是数值本身: 而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对 ...
- 微信小程序——选中状态的切换
加入购物车的时候,往往会有产品相关属性的选择,比如:尺寸,规格等.像我做的项目中,就有一个门店的选择,如下图: 我们如何做到当前点击的这个高亮呢?今天就讲一下如何实现这个功能. 思路: 1.定义一个高 ...
- 数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
题目描述 数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出. 输入描述: 先输入键值对的个数然后输入成对的index和value值 ...
- 关于Unity中拖尾渲染器的使用
拖尾渲染器 是一个组件,能够帮我们绘制出拖尾的效果. 就是跟在运动物体后面的东西,前进的过程中,末尾的不断消失,前面的不断生成,有一个长度.长度是以时间计算的,从末尾到头有多少秒的时间就是拖尾的长度. ...
- Mayi_XPath编写规则学习
XPath编写规则学习 辅助工具:firefox安装findbugs,view Xpath firefox :Xpath验证方式:$x("xpath"); 粘贴xpath语句回 ...
- Linux:Tomcat报错: Error creating bean with name 'mapScheduler' defined in ServletContext resource 的解决方法
2013-12-31 14:22:28 [ERROR] [ContextLoader.java->initWebApplicationContext(220) Context initializ ...
- 计算机网络——链路层协议
一. 链路层的功能 可靠交付:在高差错的链路,如无线链路,可以进行可靠交付:对于其它的有线,可以是多余的: 流量控制:防止接收方的缓存区溢出,帧丢失: 差错检测与差错纠正:在硬件上实现了: 二.多路访 ...