赋值运算符重载和拷贝构造函数 AND 浅拷贝与深拷贝

赋值运算符重载: 是用一个已经存在的对象去给另一个已经存在并初始化(调用过构造函数)的对象进行赋值。

拷贝构造函数:其实本质还是构造函数,用一个已存在的对象去构造一个原先不存在的对象。

string a("hello");

string b("world");

string c =a ;   //拷贝构造函数

c = b;           //调用赋值函数

一般来说是在数据成员包含指针对象的时候,应付两种不同的处理需求的 一种是复制指针对象,一种是引用指针对象

copy大多数情况下是复制,=则是引用对象的     
例子:  
  class   A  
  {  
          int   nLen;  
          char   *   pData;  
  }  
  显然  
  A   a,   b;  
  a=b的时候,对于pData数据存在两种需求  
  第一种copy  
      a.pData   =   new   char   [nLen];  
      memcpy(a.pData,   b.pData,   nLen);  
  另外一种(引用方式):  
      a.pData   =   b.pData

一、拷贝构造函数

class CExample
{
public:
    CExample(){pBuffer=NULL; nSize=0;}
    ~CExample(){delete pBuffer;}
    void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
    char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
    int nSize;
};

int main(int argc, char* argv[])
{
    CExample theObjone;
    theObjone.Init40);
    
    //现在需要另一个对象,需要将他初始化称对象一的状态
    CExample theObjtwo=theObjone;
    ...
}

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

其完成方式是内存拷贝,复制所有成员的值。

完成后,theObjtwo.pBuffer==theObjone.pBuffer。

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。

提供了拷贝构造函数后的CExample类定义为:

class CExample
{
public:
    CExample(){pBuffer=NULL; nSize=0;}
    ~CExample(){delete pBuffer;}
    CExample(const CExample&); //拷贝构造函数
    void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
    char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
    int nSize;
};

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

浅拷贝与深拷贝

用一句简单的话来说就是:浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间;深拷贝不但对指针进行拷贝,

而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

浅拷贝(位拷贝)会出现什么问题呢?

引起的问题:1:b.m_data 原有的内存未被释放,造成内存泄露

2:b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方,对象不独立了

3: 对象被析构是,m_data被析构两次。

实例分析:

后面部分转载:http://blog.csdn.net/feitianxuxue

 

浅拷贝:也就是在对象复制时,只是对对象中的数据成员进行简单的赋值,如果对象中存在动态成员,即指针,浅拷贝就会出现问题  

#include <stdio.h>
  
class A
{
 public:
  A() // 构造函数,p指向堆中分配的一空间
 {
   m_data = new char(100);
   printf("默认构造函数\n");
 }
   ~A() // 析构函数,释放动态分配的空间
 {
   if(m_data != NULL)
   {
   delete m_data;
   m_data = NULL;
   printf("析构函数\n");
   }
 }
private:
   char *m_data; // 一指针成员
};

int main()
{
   A a;
   A b(a); // 复制对象,出现问题
   return 0;
}

深拷贝:对于深拷贝,针对成员变量存在指针的情况,不仅仅是简单的指针赋值,而是重新分配内存空间

#include <stdio.h>
  #include <string>
  
  class A
  {
   public:
   A() // 构造函数,p指向堆中分配的一空间
   {
   m_pdata = new char(100);
   printf("默认构造函数\n");
   }
  
   A(const A& r)
   {
   m_pdata = new char(100); // 为新对象重新动态分配空间
   memcpy(m_pdata, r.m_pdata, strlen(r.m_pdata));
   printf("copy构造函数\n");
   }
  
   ~A() // 析构函数,释放动态分配的空间
   {
   if(m_pdata != NULL)
   {
   delete m_pdata;
   printf("析构函数\n");
   }
   }
  
   private:
   char *m_pdata; // 一指针成员
  };
  
  int main()
  {
   A a;
   A b(a); // 复制对象,不仅是数据成员的赋值,内存空间重分配
   return 0;
  }

时间: 2024-08-14 06:34:13

赋值运算符重载和拷贝构造函数 AND 浅拷贝与深拷贝的相关文章

C++拷贝构造函数(浅拷贝、深拷贝)

下面举一个简单的例子说明对象之间的拷贝(此例中没有自定义拷贝构造函数,在调用拷贝构造函数的时候,编译器会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝)浅拷贝: #include<iostream> using namespace std; class CExample { private:int a; public: CExample(int b) { a=b; } void Show() { cout<<a<<endl; } }; int main(

c++拷贝构造函数(浅拷贝和深拷贝)

对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=88; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #include <iostream> using namespace std; class CExample { private:      int a; public:      CExample(int b)      { a=b;}      void Show ()      {    

C++拷贝构造函数:浅拷贝与深拷贝

在介绍C++浅拷贝与深拷贝之前,我们先引出C++的拷贝构造函数. C++拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用.用于在建立一个新的对象时,使用一个已经存在的对象来初始化这个新对象.因为拷贝构造函数时特殊的构造函数,所以其没有返回值类型,且名称与类名相同:该函数只有一个参数,即此类对象的引用:所有类都必须有一个拷贝构造函数,如果没有自动以拷贝构造函数,系统会自动产生一个默认拷贝构造函数. 自定义拷贝构造函数的一般形式为: 类名::类名(const 类名& 对象名) { 函数体:

拷贝构造函数(二)——深拷贝与浅拷贝

拷贝构造函数(一)--哲学三连:http://www.cnblogs.com/tenjl-exv/p/8017814.html 拷贝构造函数(二)--深拷贝与浅拷贝:http://www.cnblogs.com/tenjl-exv/p/8017909.html 拷贝构造函数(三)--重载赋值运算符:http://www.cnblogs.com/tenjl-exv/p/8017983.html

C++11 指针成员与拷贝构造(浅拷贝与深拷贝)

[1]浅拷贝 一直以来,设计一个类,个人认为,最能体现水平的地方在于:类中含有指针成员变量. 如下一个典型的浅拷贝示例: 1 #include <iostream> 2 using namespace std; 3 4 class HasPtrMem 5 { 6 public: 7 HasPtrMem() : d(new int(0)) 8 {} 9 ~HasPtrMem() 10 { 11 delete d; 12 d = nullptr; 13 } 14 15 int* d; 16 };

c++拷贝构造函数、赋值运算符=重载、深拷贝与浅拷贝

 关键词:构造函数,浅拷贝,深拷贝,堆栈(stack),堆heap,赋值运算符 摘要: 在面向对象程序设计中,对象间的相互拷贝和赋值是经常进行的操作. 如果对象在申明的同时马上进行的初始化操作,则称之为拷贝运算.例如: class1 A("af"); class1 B=A; 此时其实际调用的是B(A)这样的浅拷贝操作. 如果对象在申明之后,在进行的赋值运算,我们称之为赋值运算.例如: class1 A("af"); class1 B; B=A; 此时实际调用的类

拷贝构造函数(三)——重载赋值运算符

拷贝构造函数(一)--哲学三连:http://www.cnblogs.com/tenjl-exv/p/8017814.html 拷贝构造函数(二)--深拷贝与浅拷贝:http://www.cnblogs.com/tenjl-exv/p/8017909.html 拷贝构造函数(三)--重载赋值运算符:http://www.cnblogs.com/tenjl-exv/p/8017983.html 关于拷贝函数中的赋值操作符重载  以下讨论中将用到的例子: 1 class CExample 2 { 3

c++类的拷贝、赋值与销毁(拷贝构造函数、拷贝赋值运算符析构函数)

拷贝构造函数     如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数. 拷贝构造函数第一个参数必须是一个引用类型.此参数几乎总是一个const的引用.拷贝构造函数在几种情况下都会被隐式地使用.因此,拷贝构造函数通常不应该是explicit的. 合成拷贝构造函数 与合成默认构造函数不同,即使我们定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数. 对某些类来说,合成拷贝构造函数用来阻止我们拷贝该类类型的对象.而一般情况,合成的拷贝构造函数

拷贝构造函数的重载

形式:Class_name(const Class_name & other){};//他接受一个指向类对象的常量应用作为参数.  const关键字的作用是保护other对象中的内容不发生变化. 1.何时调用拷贝构造函数: 新建一个对象并将其初始化为同类现有对象时,拷贝构造函数都将被调用. StringBad ditto(motto); StringBad metoo = motto; StringBad also = StringBad(motto); StringBad * pStringB