我们都知道两个指针指向同一个变量时如果一个指针被释放那么另一个就会出问题

为了说明问题我做了一个很恶心的小例子

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++ 副本构造器的更多相关文章

  1. 小甲鱼C++笔记(下)25-48

    二十五  二十六  二十七  重载 运算符重载 1. 作为成员函数 #include <iostream> using namespace std; class Add { private ...

  2. java源码解析之String类(二)

    上一节主要介绍了String类的一些构造方法,主要分为四类 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并 ...

  3. js--使用构造器函数来新建对象及操作

    通过new操作符来调用函数,来达到访问对象this值得目的,构造器将其创建的对象返回给我们. 直接上代码 //创建构造器函数 function Gadget(name, color){ this.na ...

  4. JavaSE——面向对象与面向过程、类与对象、(属性、方法、构造器)等

    一:面向对象与面向过程 二者都是一种思想,面向对象是相对于面向过程而言的. 面向过程: 1.面向过程思想强调的是过程(动作). 2.在面向过程的开发中,其实就是面向着具体的每一个步骤和过程,把每一个步 ...

  5. 6、Java类、对象、构造器、引用类型内存基本知识、引用类型值传递

    1.面向对象三大特征: 封装:encapsulation 继承:inheritance 多态:polymorphism 2.类中 数据特征(property):属性(attribute)静态的stat ...

  6. 一文了解 Java 中的构造器

    摘要:Java 也采用了构造器,并且还提供了一个垃圾收集器(garbage collector),当不再使用内存资源的时候,垃圾收集器会自动将其释放. 本文分享自华为云社区<一文带你了解 Jav ...

  7. Kafka副本管理—— 为何去掉replica.lag.max.messages参数

    今天查看Kafka 0.10.0的官方文档,发现了这样一句话:Configuration parameter replica.lag.max.messages was removed. Partiti ...

  8. Java之类的构造器(反射)

    反射: Java反射机制:指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法.这种动态获取类的内容以及动态调用对象的 ...

  9. Swift3.0P1 语法指南——构造器

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

随机推荐

  1. 2014.1.23 Discuz论坛迁移+VPS配置手记

    虽说这也不是我第一次转移这个论坛了,但毕竟还是第一次自己配置VPS,写点东西记一下 一:关于VPS的配置 1.用TeamViewer连接服务器 这个VPS的IDC自己带有一个远程控制的页面,用浏览器打 ...

  2. 单例(Singleton)模式

    最简单的单例「饿汉式」  public class Singleton{ private static Singleton instance=new Singleton();    //other f ...

  3. 神奇的decimal,也许面试会问到哦~

    这段时间忙的像狗一样,写博客的事情也就耽搁了,继续扯,为什么说decimal神奇呢,大家都知道decimal是基元类型,但是 这个decimal类型在IL中居然没有相应的IL指令,也就是说CLR根本不 ...

  4. MDX函数(官方顺序,带示例)

    MDX函数(官方顺序) 1.  AddCalculatedMembers (MDX) 返回通过将计算成员添加到指定集而生成的集. 语法: AddCalculatedMembers(Set_Expres ...

  5. nginx设置黑/白名单

    编辑nginx配置文件: server { listen ; server_name www.xxx.cn; #白名单 allow 192.168.1.200; deny all; #黑名单 #den ...

  6. 关于SUID、SGID、Sticky

    SUID属性 passwd命令可以用于更改用户的密码,一般用户可以使用这个命令修改自己的密码.但是保存用户密码的/etc/shadow文件的权限是400,也就是说只有文件的所有者root用户可以写入, ...

  7. 探究C语言中的前++和后++

    小波带您探究c语言中的前++与后++: 欢迎吐槽,欢迎加QQ463431476. 欢迎关注!  现在来探究: 咱们先看第一个 i被赋值0,i++(后++)并没有输出1.   现在i被赋值0,++i,也 ...

  8. speex进行音频去噪

    应用speex进行音频去噪,speex功能很强大,因为opus的出现,用speex进行编码/解码的人几乎没有了,但是用speex来进行降噪,去除回声,增益还是很多. 这里用speex进行音频去噪,主要 ...

  9. ANSI Common Lisp Learn

    It has been a long time that I haven't dealt with my blog. On one hand I was preparing the exams.On ...

  10. java 22 - 10 多线程之两种代码实现方式的比较与区别