深浅拷贝的区别与原理(C++)

本文详细介绍了Java中的基本数据类型与引用数据类型,重点讲解了浅拷贝和深拷贝的概念、原理及区别。通过示例代码展示了浅拷贝导致的问题以及如何通过深拷贝解决。在浅拷贝中,对象的引用会被复制,可能导致指针悬挂问题,而深拷贝则会创建对象的新副本,避免了这个问题。

 1.基本数据类型与引用数据类型

基本数据类型:整型(byte,short,int,long),浮点型(float,double),字符型(char),

布尔型(booI),字符串类(string)。

引用类型:对象(Object)、数组(Array)、函数(Function);

2.什么是浅拷贝,深拷贝以及原理

1.浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的,如果属性是引用类型,拷贝的就是内存地址
2.深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象。
原文链接:https://blog.youkuaiyun.com/weixin_43878906/article/details/108358240

具体原理如图:

 

原博主.【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法 - 听风是风 - 博客园

3.区别

1.在未定义显示拷贝构造函数的情况下,系统调用默认的构造函数——浅拷贝,它能够完成成员的一一复制。当数据成员没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两个析构函数,然而导致指针悬挂现象,此时就必须要用深拷贝。
2.深拷贝和浅拷贝的区别在于深拷贝会在堆内存中另外申请空间来存储数据,从而解决了指针悬挂问题。
3.浅拷贝只进行简单的属性值的复制。
原文链接:https://blog.youkuaiyun.com/hsh_123456789/article/details/114855509

4.深拷贝浅拷贝示例

1.浅拷贝

#include <iostream>
using namespace std;
class Test
{
    private:
        int* p;
    public:
        Test(int x)
        {
            this->p=new int(x);
            cout << "对象被创建" << endl;
        }
        ~Test()
        {
            if (p != NULL)
            {
                delete p;
            }
            cout << "对象被释放" << endl;
        }
        int getX()
        {
            return *p;
        }
        //浅拷贝(拷贝构造函数)
        Test(const Test& a)
        {
            this->p = a.p;
            cout << "浅拷贝对象被创建" << endl;
        }
};
int main(int argc, char *argv[])
{
    Test a(10);
    //会调用我们自己写的拷贝构造函数
    Test b(a);                                                                                                                                                                                                                                                                                                                                                              

    return 0;
}

 创建一个对象a,并传入一个参数,调用构造函数为这个参数构造空间,并使a.p指向这片空间。
创建一个对象b,并传入参数对象a,调用拷贝构造函数进行浅拷贝,此时b.p和a.p指向一样。当程序结束时,析构函数先释放a.p所指向空间,当释放b.p所指向空间时,空间为NULL,错误发生。

2.深拷贝

#include <iostream>
using namespace std;
class Test
{
    private:
        int* p;
    public:
        Test(int x)
        {
            this->p=new int(x);
            cout << "对象被创建" << endl;
        }
        ~Test()
        {
            if (p != NULL)
            {
                delete p;
            }
            cout << "对象被释放" << endl;
        }
        int getX()
        {
            return *p; 
        }
        //深拷贝(拷贝构造函数)
        Test(const Test& a)
        {
            this->p = new int(*a.p);
            cout << "深拷贝对象被创建" << endl;
        }
};
int main(int argc, char *argv[])
{
    Test a(10);
    //会调用我们自己写的拷贝构造函数
    Test b = a;
    return 0;
}

 创建一个对象a,并传入一个参数,调用构造函数为这个参数创建空间,使指a.p值向这片空间。创建一个对象B,并传入参数对象a,调用拷贝构造函数进行深拷贝,即取出a.p所指向的值并新创建一片空间,使b.p指向这片空间。当程序结束时,析构函数先释放a.p所指向空间,b.p所指向空间并不受影响,程序正常结束。

设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。 设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值