c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)

拷贝构造函数

今天和大家一起啊来学习一下c 中的拷贝构造函数,我们什么时候 会用到这个函数呢?当你用一个对象去构造另外一个对象的时候,或者是说你用一个对象去初始化另外一个对象的时候就用到了我们的拷贝函数,例如:

student stu("张三"); student stu2=stu;

上面使用对象stu去初始化我们新的对象stu2,这时候就涉及到对象的拷贝,如果这时候自己没有写拷贝函数,那么程序就会选择默认的拷贝函数,把stu的成员一个一个的拷贝给stu2。

c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)(1)

深拷贝和浅拷贝

我们刚刚提到了拷贝构造函数,是把已经初始化好的对象成员依次拷贝给新的对象,我们这样想可能觉得比较方便,但是我们想一个另外的问题,那就是当一个对象在初始化的时候向系统申请了资源,那么在拷贝给另外一个对象的时候会怎么样呢?我们来看一下代码;

#include<iostream> #include<string.h> using namespace std; class stu { private: int age; char *name; public: stu(int age, char *name) { this->age=age; this->name = new char[100]; strcpy(this->name,name); } void display()//打印函数 { cout<<"姓名:"<<name<<" 年龄: "<<age<<endl; } void change(char * name)//修改姓名函数 { strcpy(this->name,name); } }; int main() { stu s1(18,"张三"); cout<<"s1"; s1.display(); cout<<"s1赋值给s2"<<endl; stu s2=s1; cout<<"s2"; s2.display(); cout<<"修改姓名后"<<endl; s1.change("李四"); cout<<"s1"; s1.display(); cout<<"s2"; s2.display(); return 0; }

代码结果分析

c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)(2)

我们初始化好一个s1对象然后用它去初始化另外一个对象s2,经过打印函数我们可以看出来我们s1和s2的成员值都是一样的,这时候我们做了一个事情,修改其中一个对象的姓名,然后在打印出来发现我们两个对象的值都发生了改变,这我们想不符合我们的要求,我们希望每一个对象都是独立的。那么为什么会出现这样的情况呢?我们来分析一下拷贝函数在拷贝的时候系统内存情况

c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)(3)

初始化时内存情况

我们对象成员在拷贝的时候会复制原来对象的值给新的对象,但是如果原来的对象中有指针,就是说有申请过系统资源,那么这时候拷贝就不是把原来s1对象里面的*name的值给了s2对象对象中的*name指针,指针赋值意思就是说s1里面的name指针和s2里面的name指针值是一样的,那么换一句话说他们两个nmae指针指向同一个内存地址,如下图所示,这就为什么我们修改其中一个对象里面的名字另外一个对象的值也会更改的原因

c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)(4)

深拷贝构造函数

我们知道上面的构造函数在对象有系统资源比如说内存的时候是指向同一个地址,这不是我们想要的,所以我们引入了我们的深拷贝构造函数,就是在拷贝的时候我们当遇到需要资源的时候我们新的对象自己向系统申请单独的资源,申请完后再完成复制拷贝。这样两个对象虽然值是一样的但是我们并不是同一个资源,他们是独立的,我们在刚刚的代码上增加一个自己写的拷贝构造函数来完成我们的深拷贝。

stu(stu &s) { this->age=s.age; this->name = new char[100];//自己申请系统空间 strcpy(this->name,s.name); }

深拷贝结果分析

c语言在内存中怎么区分堆和栈(编程中深拷贝与浅拷贝的区别)(5)

从代码中我们看出来经过添加的拷贝构造函数就实现了初始化后的对象都是独立的,对其中一个对象的操作不会影响到其他的对象。

总结

我们每一个类里面都有一个默认的拷贝构造函数,它是属于浅拷贝,我们对象中有系统资源时我们需要自己写一个深拷贝的构造函数这样才会使得初始化出来的对象拥有独立的特性。

我们什么时候会用到构造拷贝函数?

1、用一个对象去构造另外一个对象。例如我们上面讲到的:

stu s1(18,"张三"); stu s2=s1;

2、当我们把一个对象作为参数传到函数中的时候。例如:函数void fun(student s);参数需要我们传一个对象进去那么我们在使用函数的时候我们把s1传进去:fun(s1),这时候我们的实参s1和我们的函数形参s就形成了一个s=s1的情况这时候就用到我们的拷贝构造函数。

3、返回一个静态对象的时候。例如函数:

stu fun() { static stu s(18,"李四"); return s; } stu s1=fun();//fun函数返回的对象复制给我们的s1这时候也用到我们的拷贝构造函数。

结语

我们的深拷贝与浅拷贝还有很多知识值得我们去深究,今天只是以一个简单的例子和代码带大家了解一下我们c 中的深拷贝与浅拷贝的区别,如果你有不一样的看法可以说出来大家一起探讨学习一下,最后感谢你的的阅读。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。