C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。下面就详细比较下三者之间的区别以及它们的具体实现

1.构造函数

构造函数是一种特殊的类成员函数,是当创建一个类的对象时,它被调用来对类的数据成员进行初始化和分配内存。(构造函数的命名必须和类名完全相同)

首先说一下一个C++的空类,编译器会加入哪些默认的成员函数

·默认构造函数和拷贝构造函数

·析构函数

·赋值函数(赋值运算符)

·取值函数

**即使程序没定义任何成员,编译器也会插入以上的函数!

构造函数可以被重载,可以多个,可以带参数;

析构函数只有一个,不能被重载,不带参数

而默认构造函数没有参数,它什么也不做。当没有重载无参构造函数时,

A a就是通过默认构造函数来创建一个对象

2.拷贝构造函数

拷贝构造函数是C++独有的,它是一种特殊的构造函数,用基于同一类的一个对象构造和初始化另一个对象。

当没有重载拷贝构造函数时,通过默认拷贝构造函数来创建一个对象

A a;

A b(a);

A b=a;  都是拷贝构造函数来创建对象b

强调:这里b对象是不存在的,是用a 对象来构造和初始化b的!!

先说下什么时候拷贝构造函数会被调用:

在C++中,3种对象需要复制,此时拷贝构造函数会被调用

1)一个对象以值传递的方式传入函数体

2)一个对象以值传递的方式从函数返回

3)一个对象需要通过另一个对象进行初始化

系统提供的默认拷贝构造函数工作方式是内存拷贝,也就是浅拷贝。这种方法如果对象中用到了需要手动释放的对象(如指针),则会出现问题。

下面说说深拷贝与浅拷贝:

浅拷贝:如果复制的对象中引用了一个外部内容(例如分配在堆上的数据),那么在复制这个对象的时候,让新旧两个对象指向同一个外部内容,就是浅拷贝。(指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用,两个对象不独立,删除空间存在)浅拷贝复制了一份对象,只复制了对象的本身

深拷贝:如果在复制这个对象的时候为新对象制作了外部对象的独立复制,就是深拷贝。深拷贝,把空间也拷贝了一份

默认的浅拷贝的情况:

class cperson
{
public :
int *a;//当a是整型变量时就不会发生浅拷贝问题
public :
  cperson(const cperson &aa)
  {
    this->a=aa.a;
  }
~cperson()
{
delete a;
a=NULL;
} };
cperson ps(ps1);//会出现错误,程序会崩溃

 原因就是浅拷贝,只复制了对象本身的内容,指针成员所指向的空间是没有拷贝的,会出现两个对象使用一个空间从而导致在释放空间的时候一个空间被释放两次

解决的方法:

1.使用深拷贝,如下例子:

class cperson
{
public :
int *a;
public :
  cperson(const cperson &aa)
  {
    this->a=new int (*(aa.a));//深拷贝
  }
~cperson()
{
delete a;
a=NULL;
} };

 2.不让它执行拷贝构造,即对象的函数传参时不要用值传递,要用引用如下面的例子

void qq(cperson ps1)
{ }
cperson ps;
qq(ps);//发生了浅拷贝,程序错误

  用引用代替后

void qq(cperson &ps1)
{ }
cperson ps;
qq(ps);//程序正确

特别要注意的是下面这种情况:

cperson qq(cperson &ps1)
{
     cperson ps2;
return ps2;
} 

  原因是为了保证能把ps2的值拿出去,ps2是临时对象,要想把它传出去就把它的值复制出去,此时又发生浅拷贝了。可以用返回一个引用解决。

cperson &qq(cperson &ps1)
{
     cperson ps2;
return ps2;
} 

但实际上尽量不要返回局部对象。

3.赋值函数

当一个类的对象向该类的另一个对象赋值时,就会用到该类的赋值函数。

当没有重载赋值函数(赋值运算符)时,通过默认赋值函数来进行赋值操作

A a;

A b;

b=a;

强调:这里a,b对象是已经存在的,是用a 对象来赋值给b的!!

赋值运算的重载声明如下:

A& operator = (const A& other),我们先来看一下下面的例子

class cperson
{
public :int *a;
public :
  cperson()
{
    a=new int(100);
}
cperson & operator=(const cperson&ps)
  {
return *this;
  }
~cperson()
{
    delete a;
    a=NULL;
};
cperson ps;
cperson ps1;
ps1=ps;

 该程序会崩溃,原因是对象中含有指针,当用一个对象给另一个对象赋值的时候,又出现了两个指针使用同一块地址空间的问题,那么如何解决呢?

我们可以通过先删除原来指针的空间,再为被赋值的对象中的指针重新分配空间,如下述代码:

class cperson
{
public :int *a;
public :
 cperson()
{
     a=new int(100);
}
cperson & operator=(const cperson&ps)
  {
         delete this->a;
this->a=new int (*(ps.a));
return *this;   }
~cperson()
{
    delete a;
    a=NULL;
};
cperson ps;
cperson ps1;
ps1=ps;

通常大家会对拷贝构造函数和赋值函数混淆,这儿仔细比较两者的区别:

1)拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。

2)一般来说在数据成员包含指针对象的时候,需要考虑两种不同的处理需求:一种是复制指针对象,另一种是引用指针对象。拷贝构造函数大多数情况下是复制,而赋值函数是引用对象

3)实现不一样。拷贝构造函数首先是一个构造函数,它调用时候是通过参数的对象初始化产生一个对象。

赋值函数则是把一个新的对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检察一下两个对象是不是同一个对象,如果是,不做任何操作,直接返回。

!!!如果不想写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,最简单的办法是将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。:

所以如果类定义中有指针或引用变量或对象,为了避免潜在错误,最好重载拷贝构造函数和赋值函数。

一句话记住三者:对象不存在,且没用别的对象来初始化,就是调用了构造函数;

                    对象不存在,且用别的对象来初始化,就是拷贝构造函数(上面说了三种用它的情况!)

                     对象存在,用别的对象来给它赋值,就是赋值函数。

本文转载于:http://blog.csdn.net/zcyzsy/article/details/52132936

C++中的构造函数,拷贝构造函数,赋值函数的更多相关文章

  1. 【c++ primer, 5e】构造函数 & 拷贝、赋值和析构

    [构造函数] 1.构造器就是创建对象时被调用的代码. 2.如果没有自定义构造器,那么编译器将自动合成一个默认的无参构造器. 3.自定义的构造器不允许加const,所创建const的对象只有在构造器代码 ...

  2. 关于C++ 中 thread 的拷贝构造函数

    起因来自于<C++并发编程实战>的这样一个例子 #include <thread> #include <iostream> #include <stdexce ...

  3. C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数

    构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...

  4. Python中的深浅拷贝,赋值及引用

    简单来说,若对象a中存的是列表或字典等可变对象,b对a的浅拷贝只是对对象第一层的复制,修改b第二层的元素仍然会影响两个对象. 深拷贝则是不会影响原来的对象. import copy.copy() 浅拷 ...

  5. C++中构造函数,拷贝构造函数和赋值函数的区别和实现

    C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象 ...

  6. 【C++】拷贝构造函数和赋值符函数

    在C++中,调用拷贝构造函数有三种情况: 1.一个对象作为函数参数,以值传递的方式传入函数体. 2.一个对象作为函数返回值,以值传递的方式从函数返回. 3.一个对象用于给另外一个对象进行初始化(复制初 ...

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

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

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

    我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类:   class CTe ...

  9. C++ 类 & 对象-类成员函数-类访问修饰符-C++ 友元函数-构造函数 & 析构函数-C++ 拷贝构造函数

    C++ 类成员函数 成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义. 需要强调一点,在 :: 运算符之前必须使用类名.调用成员函数是在对象上使用点运算符(.),这样它就能操作与 ...

随机推荐

  1. 中国用户通过rchange用银联充值到PerfectMoney再给BTC-E充值进行搬砖的方法

    最近迷上了比特币这个疯狂的东西,相信很多技术人员都感兴趣. 比特币.莱特币钱包下载和把数据迁移到C盘以外其他盘的方法. 莱特币和山寨币的原理跟比特币基本上一样,可以参考这个方法进行,莱特币的钱包数据迁 ...

  2. win7 安装.Net framework 4.0出现 安装不成功,错误代码0x80240037 的解决方法

    1.安装说明 系统:win7 64位 安装包:dotNetFx40_Full_x86_x64.exe(.Net framework 4.0) 出现的问题:在win7 上安装dotNetFx40_Ful ...

  3. USB开发库STSW-STM32121文件分析

    hw_config.c: 该文件中包含系统配置的函数. usb_desc.c:各种描述符 usb-endp.c:就两个函数分别处理端点1的IN和端点2的OUT. usb_istr.c: 该文件中只有一 ...

  4. 05: 配置yum源

    1.1 将镜像复制到本地创建yum源 1.将准备好的系统镜像放到指定的目录,本次目录指定在:/dawnfs/sourcecode 2.创建挂载目录:mkdir /mnt/yum 3.挂载镜像: mou ...

  5. 20145328《网络对抗技术》Final

    系内选拔赛write-up 1 信息隐藏 第一题图片藏东西,后缀名改txt,没有发现,改rar,发现压缩包内存在key.txt,解压提示存在密码,尝试使用修复,得到key.txt,打开获取flag,S ...

  6. shell下如何删除文件的某一列

    答:cat file | awk '{$1=null;print $0}' (删除第一列)

  7. linux下通过命令行上传文件到百度网盘

    一.环境: centos release 6.9 python 2.7.13 二.安装工具bypy sudo pip install bypy 三.使用bypy 3.1 授权 [root@ineedl ...

  8. RMQ 区间最大值 最小值查询

    /*RMQ 更新最小值操作 By:draymonder*/ #include <iostream> #include <cstdio> using namespace std; ...

  9. The way to Go(6): Go程序的基本结构和要素

    Reference: Github: Go Github: The way to Go Go程序的基本结构和要素 helloworld.go: package main import "fm ...

  10. 【TCP/IP详解 卷一:协议】第十一章 UDP 用户数据报协议

    11.1 引言 UDP 是一个简单的 面向数据报 的运输层协议:进程的每个 输出操作 都正好产生一个 UDP数据报,并且组装成一份待发送的IP数据报. 这与 TCP 不一样,它是 面向流字符 的协议, ...