构造函数,拷贝构造和赋值运算符‘=‘的区别

例子

class CExample  

{

private: 

  char *pBuffer;   //类的对象中包含指针,指向动态分配的内存资源 

  int nSize; 

public:  

  CExample()   {pBuffer=NULL;nSize=0;}

  ~CExample()  {delete pBuffer;}  

  void Init(int n)  { pBuffer=new char[n]; nSize=n;}

};   

int main( )  

 {   

CExample theObjone;           //对象创建调用构造函数

theObjone.Init(40);    

CExample theObjtwo=theObjone; //对象复制(因初始化),调用拷贝构造函数

        (有指针成员,使用默认拷贝构造有缺点(仅复制指针),故要用自定义的)

CExample theObjthree;  

theObjthree.Init(60);   

theObjthree=theObjone;        //对象赋值操作(因非初始化),调用赋值运算符

         (有指针成员,使用默赋值符“=”有缺点(旧指针被丢弃),故要重载运算符)

}

注意:"="号的两种不同使用,初始化和赋值

第三行也用到了"="号,该"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号()表示。而最后一行的"="号是赋值符,使用默认赋值符"=",是把被赋值对象的原内容被清除,并用右边对象的内容填充。

 

构造函数  主要用来在创建对象时, 即为对象成员变量赋初始值 

 

拷贝构造函数 形式为X(X&),用来完成基于同一类的其他对象的构建及初始化

一个对象需要通过另外一个对象进行初始化,调用拷贝构造函数。

初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作符共同实现的


默认拷贝构造函数(浅拷贝)

CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。

调用默认拷贝构造含,  其完成方式是内存拷贝(浅拷贝),复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。   即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了

这样不符合要求,对象之间不独立了,并为空间的删除带来隐患(产生野指针


自定义拷贝构造函数(深拷贝)

因此可以在构造函数中添加操作来解决指针成员的问题,即自定义的拷贝构造函数   

//自定义拷贝构造函数
CExample::CExample(const CExample& RightSides)    
{   
 nSize=RightSides.nSize;  //复制常规成员 
 pBuffer=new char[nSize]; //复制指针指向的内容   
 memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));   
}

这样,定义新对象,并用已有对象初始化新对象时,CExample(const CExample& RightSides)将被调用,而已有对象用别名RightSides传给构造函数,以用来作复制。    

原则上,应该为所有包含动态分配成员的类都提供自定义的拷贝构造函数

注意:内存拷贝函数void *memcpy(void *dest, constvoid *src, size_t n)

 

默认赋值操作符"="

//赋值操作符重载  
CExample & CExample::operator = (const CExample& RightSides)   
{   
 nSize=RightSides.nSize;      //复制常规成员   
 char *temp=new char[nSize];//复制指针指向的内容(默认=的缺点)   
 memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));   
 delete []pBuffer;    //删除原指针指向内容(避免内存泄露)
          
 pBuffer=NULL;     //同时把原指针置为NULL(避免野指针)
 pBuffer=temp;      //建立新指向  
 return *this ;
}  

"="的缺省(默认)操作只是将成员变量的值相应复制,旧的值被自然丢弃    

最后一行的"="表示赋值操作,将对象theObjone的内容复制到对象theObjthree,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。   

由于对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放(导致内存泄露)。指针的值被复制了,但指针所指内容并未复制(导致新指针指的内容丢了

即产生两方面的问题:丢弃旧指针(导致内存泄露),仅复制新指针(导致内容丢了)

因此,包含动态分配成员的类除了提供拷贝构造函数外,还应该考虑重载"="赋值操作符号

 

 

重载"="赋值操作符

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数是用来创建一个新对象并将其初始化为给定对象的副本的特殊成员函数。它通常用于以下情况: - 当一个对象通过值传递给函数或以值的形式返回时 - 当一个对象用另一个对象进行初始化时 - 当一个对象作为另一个对象的成员进行初始化时 对于类`Person`的拷贝构造函数,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给新创建的对象的`name_`成员变量。 赋值运算符是用于将一个对象的值分配给另一个已经存在的对象的成员函数。它通常用于以下情况: - 当一个对象被另一个对象赋值时 - 当一个对象作为另一个对象的成员进行赋值时 对于类`Person`的赋值运算符,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给当前对象的`name_`成员变量。然后,它将返回一个指向左侧运算对象的引用,以支持连续赋值的操作。 如果在类定义中没有显式定义拷贝构造函数赋值运算符,编译器会为类生成默认的拷贝构造函数赋值运算符。此外,我们还可以使用`=default`来显式要求编译器生成合成的拷贝构造函数赋值运算符。这将使用默认的实现来完成拷贝赋值操作。 总之,拷贝构造函数用于创建一个对象的副本,而赋值运算符用于将一个对象的值赋给另一个已经存在的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++拷贝构造函数拷贝赋值运算符](https://blog.csdn.net/xiongya8888/article/details/89424224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值