C++类的副本构造器之深复制(拷贝)与浅复制(拷贝)
来源:互联网 发布:飞向札幌的班机js 编辑:程序博客网 时间:2024/05/16 04:27
副本构造器可实现将一个对象复制到另一个对象,可用point n(3);point p(n);实现对象的赋值。在这里,复制包括两种,一种是浅复制,一种是深复制。
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。如果对象里不存在有成员变量动态分配内存的情况,就不会出现如上问题,无须讨论深拷贝和浅拷贝问题。
对于动态开辟了内存的对象而言,所谓浅复制是指将对象两个对象指向同一块内存,即对象p和n的成员变量指向同一块int型的内存。
代码如下:
class point{private:int *y;public:point(int y);point();int getY();point(const point &other); //副本构造器~point(); //析构器};int main(){point n(3); //调用构造器point p(n);//调用副本构造器n.~point(); //析构器cout<<p.getY()<<endl;}point::point(){this->y=new int;*(this->y)=0;}point::~point(){delete y;}point::point(int y){this->y=new int;*(this->y)=y;}int point::getY(){return *y;}point :: point(const point &other){this->y=other.y; //将传入对象指针y里的地址赋值给本对象指针y,本对象y指向传入对象y所指向的内存。}
运行,结果打印的数据并不是期望的3.
为什么出现这种情况?原因在于,p对象的指针y指向了n对象指针y所指向的内存区。当n对象调用析构器(被销毁)后,p对象y所指向的地址内容是一个随机数。
既然拷贝指针值的方法有问题,那么,将对象的值拷贝到另一个对象呢?所谓的深复制是指,去重新构建对象的内容,将对象复制给另一个对象,而不是简单的复制指针值。
代码如下:
class point{private:int *y;public:point(int y);point();int getY();point &operator=(const point &other);point(const point &other);~point();};int main(){point n(3); //构造器point p(n); //副本构造器n.~point(); //析构器cout<<p.getY()<<endl;point p2=p; //调用赋值操作符函数p.~point(); cout<<p2.getY()<<endl;}point::point(){this->y=new int;*(this->y)=0;}point::~point(){delete y;}point::point(int y){this->y=new int;*(this->y)=y;}int point::getY(){return *y;} //赋值操作函数,假设当前对象已经被提前创建出来并经过了初始化(y所指向的内存已被创建)point& point::operator=(const point &other){ if(this==&other) return *this;delete y;y=NULL;y=new int;*(this->y)=*(other.y); //假设y所指向的内存已被newreturn *this;} //副本构造器point :: point(const point &other){ //不需要假设对象已被创建并且初始化了,副本构造器当前的对象肯定是新建的this->y=new int; //这里new 本对象y指向的内存是因为调用副本构造器的对象并没有调用构造器。*(this->y)=*(other.y);}
结果:3
3
和第一个代码的副本构造器不同之处在于重新分配了一块内存,并将n对象的内容拷贝(复制)给对象p.
p(n)调用的是副本构造器,在深拷贝中必须在副本构造器里开辟一段内存放数据,如果不开辟虽然编译器检查不出错误,可通过编译,但在运行的时候出现错误:段错误 (核心已转储)。一定要记住分配需要的内存!
而对于赋值操作符函数和一般的成员函数一样,是假设当前对象已被创建出来并经过了初始化(若所假设创建的内存大小不合适,可将对应的delete重新new即可,给指针成员变量创建内存默认在构造器里,并不是说只能在构造器里,需要的话在其他成员函数里先delete掉再重新分配就行)。而副本构造器不需要假设对象已被创建并且初始化了,副本构造器当前的对象肯定是新建的。
调用副本构造器错误的写法:
point n(3);//初始化n
point p(2); //初始化p
p(n);//调用副本构造器再次初始化p
编译:error: no match for call to ‘(point) (point&)’ p(n);
可见调用副本构造器初始化一个对象时,被初始化的对象不应该已经被初始化过(调用构造器)。这一点也说明了,调用副本构造器之前对象并没有调用构造器,所以必须在副本构造器中要为成员变量创建内存。
- C++类的副本构造器之深复制(拷贝)与浅复制(拷贝)
- 【C++】拷贝构造函数之浅复制与深复制
- C++类对象之间复制,拷贝构造函数的作用,深拷贝与浅拷贝
- C++复制构造函数详解(深拷贝,浅拷贝)
- c++复制构造函数(浅拷贝、深拷贝)
- C++之--拷贝(复制)构造函数
- 复制构造函数&深拷贝&浅拷贝
- 拷贝构造函数的 深/浅 复制
- 拷贝(复制)构造函数
- C++类对象的复制-拷贝构造函数(深拷贝,浅拷贝)
- C++类对象的复制-拷贝构造函数(深拷贝,浅拷贝)
- C++类对象的复制-拷贝构造函数(深拷贝,浅拷贝)
- C++类对象的复制-拷贝构造函数(深拷贝,浅拷贝)
- C++类对象的复制-拷贝构造函数(深拷贝,浅拷贝)
- C#中浅拷贝与深拷贝(复制)
- 复制构造函数的浅拷贝和深拷贝
- c++中类的位拷贝与拷贝构造函数(浅拷贝与深拷贝)
- 类对象的浅拷贝和深拷贝(浅复制和深复制)
- OpenStack Liberty High Availability 概述和指导-第二部分
- 关于无锁队列的使用
- leetcode_c++:Word Ladder II(126)
- linux下fork()函数讲解
- System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本
- C++类的副本构造器之深复制(拷贝)与浅复制(拷贝)
- 《c陷阱与缺陷》1-3章笔记
- 软件设计模式之-观察者模式与被观察者模式
- 基于51单片机的超声波测距仪
- Sublime Text 快捷键
- Struts2总结
- 居中 margin:0 auto与text-align:center的区别
- 直接选择排序java实现
- 开博客的第一天