『数据结构与算法』C++中深复制和浅复制(深拷贝和浅拷贝)!

C++中深复制和浅复制(深拷贝和浅拷贝)!

文章目录

    • 一. 复制构造函数
    • 二. 合成复制构造函数
    • 三. 浅复制
    • 四. 深复制
    • 五. 深复制浅复制举例

一. 复制构造函数

复制构造函数又称为拷贝构造函数,它是一种特殊的构造函数。它的作用就是用一个已经生成的对象初始化另一个同类的对象

变量的初始化:int a=10; int b=a;
对象的初始化:Point pt1(10,20); Point pt2=pt1;

复制构造函数定义的一般形式为:

类名(const 类名& obj)
{
函数体
}
class Point//Point类
{ 
public:
    Point() : x(0), y(0) {}                   //默认构造函数
    Point(const Point &r) : x(r.x), y(r.y) {} //复制构造函数
    Point(int a, int b) : x(a), y(b) {} 	  //带参数构造函数
private:
    int x, y;
};

复制构造函数有且只有一个本类类型对象的引用形参,通常使用const限定。因为复制构造函数只是复制对象,没有必要改变传递来的对象的值。

复制构造函数的功能是利用一个已知的对象来初始化一个被创建的同类的对象。与复制构造函数对应的对象的定义形式为:

类名 对象名1(类对象1), 对象名2(类对象2),......;

=======================================================================================
对象赋值和对象复制的区别:
►对象的赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。
►对象的复制则是从无到有地建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)。

二. 合成复制构造函数

每个类必须有一个复制构造函数。如果类没有定义复制构造函数,编译器就会自动合成一个,称为合成复制构造函数(synthesized copy constructor)

  • 与合成默认构造函数不同,即使定义了其他构造函数,编译器也会合成复制构造函数。
  • 合成复制构造函数的操作是:执行逐个成员初始化,将新对象初始化为原对象的副本。

以下3种情况会使用复制构造函数。
①用一个对象显式或隐式初始化另一个对象。
► C++支持两种初始化形式:复制初始化和直接初始化。复制初始化使用等号(=),而直接初始化将初始化式放在圆括号中。
►复制初始化和直接初始化是有区别的:直接初始化会调用与实参匹配的构造函数;而复制初始化总是调用复制构造函数。

②函数参数按值传递对象时或函数返回对象时。
►当函数形参为对象类型,而非指针和引用类型时,函数调用按值传递对象,即编译器调用复制构造函数产生一个实参对象副本传递到函数中。
►类似地,以对象类型作为返回值时,编译器调用复制构造函数产生一个return语句中的值的副本返回到调用函数。

③根据元素初始化式列表初始化数组元素时。
►如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用常规的大括号的数组初值列表形式来初始化数组时,则使用复制初始化来初始化每个元素。

总的来说,正是有了复制构造函数,函数才可以传递对象和返回对象,对象数组才能用初值列表的形式初始化。

Point pt1(10,20);
Point pt2=pt1; //复制初始化
Point pt3(pt1); //直接初始化

三. 浅复制

若复制对象但未复制资源内容称为浅复制。

  • 如图所示,比如下面有一个Point类型的对象a,在这个Point类中它有一个数据成员(是一个指针)p,指针肯定要指向一个对象的(占用一个定的存储空间),假设p指向的存储空间如图。所谓的浅复制就是将a这个对象成员p的值拷贝给b这个对象的成员p(b也是Point类型,里面也有一个指针成员变量p),浅复制就是把a对象里的p的值拷贝给b对象p的值,因为a里p的值是一个地址,相当于把这个地址给拷贝了。两个指针存放的的地址一样,意味着她们指向同一段内存区域
  • 存在一个问题:当我们撤销这2个对象的时候,首先撤销a对象,连同a对象里的成员p指向的内存空间一起撤销了。接着又撤销b对象,因为b中p指向的存储空间已经被撤销过了,继续撤销,相当于同一段内存空间怎么被撤销了2次?这就是浅复制的问题。
『数据结构与算法』C++中深复制和浅复制(深拷贝和浅拷贝)!_第1张图片

四. 深复制

如果一个拥有资源(如用new得到的动态内存)的类对象发生复制的时候,若对象数据与资源内容一起复制,称为深复制。

  • 如图所示,和上面同一个例子。比如下面有一个Point类型的对象a,在这个Point类中它有一个数据成员(是一个指针)p,指针肯定要指向一个对象的(占用一个定的存储空间),假设p指向的存储空间如图。所谓的深复制就是将a这个对象成员p的值拷贝给b这个对象的成员p(b也是Point类型,里面也有一个指针成员变量p),深复制就是把a对象里的p指针重新分配块段内存空间(存储空间大小和a指向的一样)。此时两个对象中的指针指向存储空间是分开的,不是同一块存储空间。
  • 深复制不会存在刚刚浅复制存在的问题。
『数据结构与算法』C++中深复制和浅复制(深拷贝和浅拷贝)!_第2张图片

上面介绍说,如果自己不定义复制构造函数,系统会自动生成复制构造函数,为什么还要定义复制构造函数了呢?问题就是就是出在深复制和浅复制这个地方。系统自动生成的复制构造函数采用的初始化方式都是浅复制方式。那么当类里面有一个数据成员是指针的情况下,这时候就会出现问题了,我们自定义复制构造函数就是为了实现这个深复制。

五. 深复制浅复制举例

#include <iostream>
#include <string.h>
using namespace std;

class CA
{
public:
    CA(int b, char *cstr) //普通构造函数
    {
        a = b;
        str = new char[b]; //私有成员数据str指向生成的一个长度为b的字符数组;
        strcpy(str, cstr); //将cstr拷贝到str里面;
    }
    CA(const CA &C) //复制构造函数
    {
        a = C.a;
        str = new char[a]; //=========================深复制,浅复制则写成str=C.str;
        if (str != 0)      //这里判断一下分配存储空间成功没
            strcpy(str, C.str);
    }
    void show()
    {
        cout << str << endl;
    }
    ~CA() //析构函数
    {
        delete str; //将各个对象指向的字符数组空间撤销,如果是浅复制这里出错误。
    }

private:
    int a;     //私有数据成员,整形;
    char *str; //私有数据成员,字符型指针,存在一个指针变量,这时候要考虑深复制和浅复制。
};

int main()
{
    CA a(10, "hello");
    CA b = a;
    b.show();
    system("pause");
    return 0;
}
hello
请按任意键继续. . .

你可能感兴趣的:(数据结构与算法,数据结构,c++,深复制浅复制)