读书频道 > 网站 > 网页设计 > Visual C++入门很简单
2.复制构造函数
13-08-22    奋斗的小年轻
收藏    我要投稿   

本文所属图书 > Visual C++入门很简单

本书介绍Visual C++的函数调用形式、面向对象编程、MFC工作原理、开发软件流程及一些实用开发技巧。全书共15章,分为4篇。第1篇介绍Visual C++开发环境、C++语法基础及MFC运行机制;第2篇介绍利用Visual Stud...立即去当当网订购

在结构体(struct)被初始化的那节讲到相同结构体的变量值可以整个赋给另一个变量,比如声明结构体struct name{…}; 后定义了它的两个变量,如name na1; name na2; 。这时na1已经被初始化,而对na2 的初始化可以采用直接赋值:na2 = na1;。

类似地,在C++ 中对于相同类定义的不同对象,可以用一个对象去构造另一个对象。

此时被赋值的另一个对象调用的构造函数就称为复制构造函数,具体代码如下,其结果如图3.17 所示。


01 #include <iostream>
02  using namespace std;
03 
04 class Adult
05 {
06 public:
07  Adult(){}       // 默认构造函数
08   Adult(int z){Z = z;}    //带参构造函数
09   void display() {cout<<Z<<endl;}  // 输出Z 值
10 
11   ~Adult(){}       //析构函数
12 private:        // 成员变量为私有
13   int Z;
14 };
15 
16 int main()
  ·77·
17 {
18  Adult adult1(1);     // 定义一个对象
19  Adult adult2;      // 定义第二个对象
20   adult2 = adult1;      //整体赋值
21  adult1.display();     // 输出
22   adult2.display();
23   return 0;
24 }

两者的结果一模一样,读者其实可以想象出默认的复制构造函数中的代码就是一个个成员变量值复制动作。
接下来再看下一段代码:
01 #include <iostream>
02 #include <string>
03  using namespace std;
04 
05 class Adult
06 {
07 public:
08  Adult(){Z = &X;}   //默认构造函数
09   Adult(int
*
 z){Z = z;}      // 重载构造函数
10   void display()//输出函数
11   {
12   cout<<
*
Z<<endl;
13   }
14 
15   ~Adult()     //析构函数
16   {
17   if(Z != NULL)    //如果指针不为空就释放它
18     delete [] Z;
19   }
20 public:       //成员变量为私有
21  int X;       //成员变量
22   int
*
 Z;      //指针
23 };
24 
25 void Delivery( Adult ad )     // 传递对象(赋值)
26 {
27  ad.display();    //输出
28 }
29 int main()
30 {
31   int
*
 address;    //名为address的整型指针
32    address = new int[1];    //声明1 个字节的内存
33 
*
address = 1;     //将指针指向内存,赋值为1
34   
35   Adult adult1(address);   //定义一个对象
36   Delivery(adult1) ;    // 传递对象
37   adult1.display();     //输出
38   return 0;
39 }

由于第36行的行为使得对象adult1 和ad 中的Z 整型指针指向的是同一块内存(因为被赋值)。另外 ad 是个局部变量,只要在第 26~28行这个函数作用区间结束,ad 就会被销毁(调用Adult的析构函数,同时对象ad 中Z 指向的那块内存也会被释放)。但是在37行又要输出对象adult1 中Z 指向内存的值,因为指针指向的内存都不存在了,被输出的值不正确,如图3.18 所示。

 

为了让读者更清晰地明白上面这段代码出现bug 的原因,在此列出它的后台管理内存流程,如图3.19 所示。

注意:当局部变量ad 一经释放,路径2 指向的变量number内存区也会被释放掉(number没有啦)。而当adult对象要通过路径1 访问变量number时已无对象在那里。

 

对于这种情况,默认的复制构造函数就不再起作用,读者不得不自己写一个复制构造函数,它的书写形式如下:
类名 (类名 &  对象名);

基于此重新修改上面代码,得到如下形式,经运行结果正确(输出都是1 ),它的原理如图3.20 所示。不同对象指针变量会指向不同的内存区,所以不管哪个先被释放都不会影响另一个,两者相互独立。
01 #include <iostream>     //下面加粗为添加部分
02 #include <string>
03  using namespace std;
04 
05 class Adult
06 {
07 public:
08   …
09   Adult(Adult & adult2);     //复制构造函数
10   …
11 };
12 
13  Adult::Adult(Adult & adult2)    //复制构造函数定义体
14 {
15   Z = new int[1];     //重新分配一块内存
16 
*
Z = 1;        //仍然赋值为1
17 }
18   …
19 int main()
20 {
21   …
22   return 0;
23 }

 

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.3 功能
下一篇:1.5 小结
相关文章
图文推荐
JavaScript网页动画设
1.9 响应式
1.8 登陆页式
1.7 主题式
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站