c++ 副本构造器
我们都知道两个指针指向同一个变量时如果一个指针被释放那么另一个就会出问题
为了说明问题我做了一个很恶心的小例子
class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
delete ptrInt;
} C(const C& c)
{ }
int * ptrInt;
int valueInt;
private: }; int main()
{
C c1();
C c2();
c2=c1;
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}
这是把c1赋值给了c2后把指针ptrInt的值输出和valueInt输出,再把c1的指针给delete,valueInt赋值为0
再输出c2的ptrInt和valueInt就会发现指针有问题,看一下输出结果:
已经不对了吧。
为了解决这样的问题我第一个想到的就是重载操作符=
C& operator=(const C &c)
{
if(this!=&c)
{
delete ptrInt;
ptrInt = new int;
*ptrInt= *c.ptrInt;
valueInt=c.valueInt;
}
return *this;
}
完整代码
class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
delete ptrInt;
} C(const C& c)
{ }
int * ptrInt;
int valueInt; C& operator=(const C &c)
{
if(this!=&c)
{
delete ptrInt;
ptrInt = new int;
*ptrInt= *c.ptrInt;
valueInt=c.valueInt;
}
return *this;
}
private: }; int main()
{
C c1();
C c2();
c2=c1;
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}
再看一下输出结果:
这下就正确了吧,但是如果 我们在main函数里做一个修改
int main()
{
C c1();
C c2=c1;//这里直接赋值
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}
这样后错误就又和之前一样了,为什么呢,
编译器将在c类里找一个副本构造器(copy constructor)如果找不到它会自己创建一个,
即使我们对操作符=进行了重载也没有用,由编译器自己创建的副本构造器仍会以"逐们复制"
的方式把c1赋值给c2
这样我们还要重新实现这个副本构造器,
className(const className &cn);
我是这样做的
C(const C& c)
{
*this=c;
}
这里的=其实就是调用的重载的=方法
完整代码
class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
delete ptrInt;
} C(const C& c)
{
*this=c;
}
int * ptrInt;
int valueInt; C& operator=(const C &c)
{
if(this!=&c)
{
delete ptrInt;
ptrInt = new int;
*ptrInt= *c.ptrInt;
valueInt=c.valueInt;
}
return *this;
} private: }; int main()
{
C c1();
C c2=c1;//这里直接赋值
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}
结果
c++ 副本构造器的更多相关文章
- 小甲鱼C++笔记(下)25-48
二十五 二十六 二十七 重载 运算符重载 1. 作为成员函数 #include <iostream> using namespace std; class Add { private ...
- java源码解析之String类(二)
上一节主要介绍了String类的一些构造方法,主要分为四类 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并 ...
- js--使用构造器函数来新建对象及操作
通过new操作符来调用函数,来达到访问对象this值得目的,构造器将其创建的对象返回给我们. 直接上代码 //创建构造器函数 function Gadget(name, color){ this.na ...
- JavaSE——面向对象与面向过程、类与对象、(属性、方法、构造器)等
一:面向对象与面向过程 二者都是一种思想,面向对象是相对于面向过程而言的. 面向过程: 1.面向过程思想强调的是过程(动作). 2.在面向过程的开发中,其实就是面向着具体的每一个步骤和过程,把每一个步 ...
- 6、Java类、对象、构造器、引用类型内存基本知识、引用类型值传递
1.面向对象三大特征: 封装:encapsulation 继承:inheritance 多态:polymorphism 2.类中 数据特征(property):属性(attribute)静态的stat ...
- 一文了解 Java 中的构造器
摘要:Java 也采用了构造器,并且还提供了一个垃圾收集器(garbage collector),当不再使用内存资源的时候,垃圾收集器会自动将其释放. 本文分享自华为云社区<一文带你了解 Jav ...
- Kafka副本管理—— 为何去掉replica.lag.max.messages参数
今天查看Kafka 0.10.0的官方文档,发现了这样一句话:Configuration parameter replica.lag.max.messages was removed. Partiti ...
- Java之类的构造器(反射)
反射: Java反射机制:指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法.这种动态获取类的内容以及动态调用对象的 ...
- Swift3.0P1 语法指南——构造器
原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...
随机推荐
- Symantec Backup Exec 报"Access denied to directory xxx" Error Code E0008488
使用Symantec Backup Exec将几台Linux服务器上的RMAN备份收带时,偶尔会遇到作业备份失败的情况,检查Job History,就会发现有“Access denied to dir ...
- Sql Server之旅——第一站 那些给我们带来福利的系统视图
本来想这个系列写点什么好呢,后来想想大家作为程序员,用的最多的莫过于数据库了,但是事实上很多像我这样工作在一线的码农,对sql 都一知半解,别谈优化和对数据库底层的认识了,我也是这样... 一:那些系 ...
- 烂泥:puppet添加带密码的用户
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 前一篇文章,我们介绍了有关puppet3.7的安装与配置,这篇文章我们再来介绍下如何利用puppet添加带密码的用户. 要通过puppet添加带密码的用 ...
- Linux 多线程互斥量互斥
同步 同一个进程中的多个线程共享所在进程的内存资源,当多个线程在同一时刻同时访问同一种共享资源时,需要相互协调,以避免出现数据的不一致和覆盖等问题,线程之间的协调和通信的就叫做线程的同步问题, 线程同 ...
- pwd, cd, ls, touch, mkdir, rmdir, rm
学习Shell命令最好的资料当然的是$man, 绝对是查找命令的第一大杀器,但是我们有时只是想实现某个功能,甚至连这个命令是什么都不知道,又或者不想淹没在man里大段大段的英文里,大家可以参考Linu ...
- Linux中的SWAP交换分区
大多数 Linux 在系统安装时都会提醒并建议你划分一个 SWAP 交换分区,如果你是从 Windows 切换到 Linux 的新用户,兴许对这个 SWAP 会感到十分疑惑. SWAP 交换分区到底是 ...
- 启动mysql错误ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)
ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ ( ...
- 报表引擎API开发入门—简单程序数据集
小编最近接的项目是有关报表开发的,很想把这部分知识分享出来.希望大家能够支持我!不多说,马上进入我们今天的话题. API基本知识 小编最近项目所做的是关于一个报表软件—FineReport报表开发的一 ...
- 【2016-10-13】【坚持学习】【Day4】【模板方法模式】
今天学习模板方法模式 例子代码; 模板抽象类,定义了一套流程,有一些方法已经实现,有一些抽象方法需要继承它的子类实现 abstract class DataViewer { //抽象方法:获取数据 p ...
- webdriver的工作原理
selenium1的原理就是使用js来驱动浏览器,因为现在基本不用,所以不做过多讨论,下面是我整理的webdriver的工作原理,大致就是通过命令请求webdriver,然后webdriver通过浏览 ...