设为首页 加入收藏

TOP

8.2 实现复制构造函数
2013-10-07 12:33:49 来源: 作者: 【 】 浏览:72
Tags:8.2 实现 复制 构造 函数

8.2  实现复制构造函数

当我们动态地为类成员分配空间时,会有些不合适的对象存在于自由存储器中。就CMessage类来说,默认的复制构造函数就不合适。假设我们写出下面这两条语句:

  1. CMessage motto1("Radiation fades your genes.");  
  2. CMessage motto2(motto1); // Calls the default copy constructor 

在这里,默认复制构造函数的作用是将类对象motto1的指针成员存储的地址复制到motto2中,因为默认复制构造函数实现的复制过程只是将原来对象的数据成员中存储的数值复制到新对象中。因此,这两个对象将共享仅有的一个文本串,图8-1说明了这种情况。

在任何一个对象中对字符串进行的修改,都将被另一个对象反映出来,因为两个对象共享相同的字符串。如果motto1被销毁,那么motto2中的指针将指向已经被释放、现在可能用于其他对象的内存区域,因此肯定会发生混乱。当然,如果删除motto2,也会出现相同的问题。motto1包含的指针成员将指向一个不存在的字符串。

 
(点击查看大图)图  8-1
解决方案是提供一个类复制构造函数来代替默认版本。如下所示,我们可以在类的public部分实现该函数:
  1. CMessage(const CMessage& initM)         // Copy Constructor definition  
  2. {  
  3. // Allocate space for text  
  4. pmessage = new char[ strlen(initM.pmessage) + 1 ];  
  5.  
  6. // Copy text to new memory  
  7. strcpy(pmessage, initM.pmessage);  

记得第7章讲过,为了避免对复制构造函数的无穷调用,我们必须将形参指定为const引用。该复制构造函数首先分配足够容纳initM对象中字符串的内存,将地址存入新对象的数据成员中,然后复制初始化对象中的文本串。现在,新对象与旧对象相同,但与旧对象完全无关。

不要因为没有用另一个CMessage类对象初始化同类的对象,就认为我们是安全的,就不需要为复制构造函数烦恼。另一个潜伏在自由存储器中的"妖怪"可能在我们毫无防备的情况下,突然冒出来将我们咬住。考虑下面的语句:

  1. CMessage thought("Eye awl weighs yews my spell checker.");  
  2. DisplayMessage(thought);    // Call a function to output a message 

其中DisplayMessage()函数的定义如下所示:

  1. void DisplayMessage(CMessage localMsg)  
  2. {  
  3. cout << endl << "The message is: "  
  4. << localMsg.ShowIt();  
  5. return;  

看起来很简单,但代码中存在着致命的错误!函数DisplayMessage()所做的事情实际上与此无关,问题出在形参上面。形参是一个CMessage对象,因此调用过程中实参是通过传值方式传递的。使用默认的复制构造函数,将发生一系列事件:

(1) 创建thought对象,在自由存储器中为消息"Eye awl weighs yews my spell checker"分配空间。

(2) 调用DisplayMessage()函数。因为实参是通过传值方式传递的,所以使用默认复制构造函数创建实参的副本localMsg。现在,副本中的指针指向自由存储器中原来的对象所指向的字符串。

(3) DisplayMessage()函数结束时,局部对象localMsg不再有效,因此程序调用CMessage类的析构函数,通过释放pmessage指针指向的内存,删除这个局部对象(副本)。

(4) 从DisplayMessage()函数返回时,原来的对象thought包含的指针仍然指向刚刚被释放的内存区域。我们下次再使用原来的对象(就算我们不使用该对象,它迟早也会被删除)时,程序将表现出异常的行为。

如果某个类拥有动态定义的成员,我们又利用按值传递机制给函数传递该类的对象,那么对这个函数的任何调用都将出错。因此,我们必须无条件地遵守下面这条规则:

如果动态为本地C++(www.cppentry.com)类的成员分配空间,则必须实现复制构造函数。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇8.6.1 类接口的概念 下一篇8.5.1 定义类模板

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: