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

对于普通类型的对象来说,它们之间的复制是很简单的,例如:   int a=88;   int b=a;   而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。

   #include
   using namespace std;
   class CExample {
   private:
   int a;
   public:
   CExample(int b)
   {
   a=b;
   }
   void Show ()
   {
   cout<<a<<endl; </a<<endl;
   }
   };
   int main()
   {
   CExample A(100);
   CExample B=A;
   B.Show ();
   return 0;
   }

  运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。下面举例说明拷贝构造函数的工作过程。

   #include
   using namespace std;
   class CExample {
   private:
   int a;
   public:
   CExample(int b)
   { a=b;}
   CExample(const CExample& C)
   {
   a=C.a;
   }
   void Show ()
   {
   cout<<a<<endl; </a<<endl;
   }
   };
   int main()
   {
   CExample A(100);
   CExample B=A;
   B.Show ();
   return 0;
   }

  CExample(const CExample& C)就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。   当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:   一个对象以值传递的方式传入函数体   一个对象以值传递的方式从函数返回   一个对象需要通过另外一个对象进行初始化。   如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。   自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。   浅拷贝和深拷   在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。   深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝的例子。

   #include
   using namespace std;
   class CA
   {
   public:
   CA(int b,char* cstr)
   {
   a=b;
   str=new char;
   strcpy(str,cstr);
   }
   CA(const CA& C)
   {
   a=C.a;
   str=new char[a]; //深拷贝
   if(str!=0)
   strcpy(str,C.str);
   }
   void Show()
   {
   cout<<str<<endl; </str<<endl;
   }
   ~CA()
   {
   delete str;
   }
   private:
   int a;
   char *str;
   };
   int main()
   {
   CA A(10,"Hello!");
   CA B=A;
   B.Show();
   return 0;
   }

  深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。   浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错。   Test(Test &c_t)是自定义的拷贝构造函数,拷贝构造函数的名称必须与类名称一致,函数的形式参数是本类型的一个引用变量,且必须是引用。   当用一个已经初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用,如果你没有自定义拷贝构造函数的时候,系统将会提供给一个默认的拷贝构造函数来完成这个过程,上面代码的复制核心语句就是通过Test(Test &c_t)拷贝构造函数内的p1=c_t.p1;语句完成的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏鸿的学习笔记

python的对象引用

Every object has an identity, a type and a value. An object’s identity never cha...

713
来自专栏zlmai的专栏

搞清C++中指针、数组、字符串的关系

在一些时候,字符串、指针和数组的关系我们常常搞混,下面通过一些典型问题来展示它们间的关系。

1892
来自专栏十月梦想

变量和常亮

在函数内,变量的使用需要声明常量的作用域globay变量名(全局作用)local(局部)static(静态)

582
来自专栏企鹅号快讯

Python基础知识3:re正则表达式

正则表达式(或RE)是一种小型的、高度专业化的编程语言,内嵌在Python中,仅做字符的匹配。 1、字符类型: 普通字符和元字符; 1)普通字符:大多数的字符和...

1727
来自专栏xingoo, 一个梦想做发明家的程序员

汇编语言 手记7

CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址; 在8086PC中,内存地址由段地址和偏移地址组成。 8086CPU中有一个DS寄存器,通常用来存...

1839
来自专栏lulianqi

ArrayList List<T> T[] Array

不保证会对 ArrayList 排序。 在执行需要对 ArrayList 排序的操作(如 BinarySearch)之前,必须对 ArrayList 进行排序。

521
来自专栏码云1024

Java 程序运行过程中的内存分析

2906
来自专栏Nian糕的私人厨房

C_09 指针

内存地址:为了正确的访问内存单元上的数据,我们人为的给每个内存起上编号,这个编号就是内存的地址

745
来自专栏软件开发 -- 分享 互助 成长

C++ STL之set的基本操作

set是集合,虽然也存在键值和实值,不过两者根本就是同一个值,键值的设置完全就是为了满足红黑树的底层结构,set操作与map很像不过也有些不同。 1、 set迭...

1935
来自专栏海天一树

小朋友学Python(28):join方法和eval方法

一、join方法 语法: str.join(sequence) 功能: join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串 参数: seq...

26710

扫描关注云+社区