CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

先别运行 告诉我答案先

楼主huangyangman(庸人自扰)2006-10-13 13:50:25 在 C/C++ / C++ 语言 提问

#include   <fstream.h>  
   
  class   howmany{  
  static   int   object_count;  
  public:  
  howmany(){  
  object_count++;  
  }  
  static   void   print(const   char*   msg=0)  
  {  
  if(msg)   cout<<msg<<":";  
  cout<<"object_cout="  
  <<object_count<<endl;  
  }  
  ~howmany(){  
  object_count--;  
  print("~howmany()");  
  }  
  };  
  int   howmany::object_count=0;  
  howmany   f(howmany   x){  
  x.print("x   argument   inside   f()");  
  return   x;  
  }  
  void   main()   {  
  howmany   h;  
  howmany::print("after   construction   of   h");  
  howmany   h2=f(h);  
  howmany::print("after   call   to   f()");  
  }  
  看看你家编译器怎么做的! 问题点数:30、回复次数:36Top

1 楼Jokar(贪睡鼠)回复于 2006-10-13 13:58:30 得分 10

ms是   copy   constructor   的问题~   我想说,我家编译器相当的老,相当的不标准;Top

2 楼huangyangman(庸人自扰)回复于 2006-10-13 14:02:38 得分 0

呵呵   学习C++还真是要付出代价啊    
  还要记这记那的   男人真命苦Top

3 楼Jokar(贪睡鼠)回复于 2006-10-13 14:04:33 得分 0

男人真命苦  
  ----------------  
  女人命苦的更多~呵呵Top

4 楼Jokar(贪睡鼠)回复于 2006-10-13 14:08:36 得分 0

呵呵~其实   plus个   copy   constructor   就行了~Top

5 楼huangyangman(庸人自扰)回复于 2006-10-13 14:12:30 得分 0

你不能再说了   再说我这贴可就没人顶了  
  呵呵  
  人气最重要!~  
  Top

6 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:17:12 得分 10

所以很少用类做参数的,用引用就没问题了。Top

7 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:20:53 得分 0

faint,还有一个陷阱啊。Top

8 楼cwl_feng()回复于 2006-10-13 14:21:43 得分 0

还是养成用引用作参数的好习惯吧,但是谁能解释一下这是为什么呢?Top

9 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:22:10 得分 0

assign   constructor也是Top

10 楼Jokar(贪睡鼠)回复于 2006-10-13 14:28:09 得分 0

还是养成用引用作参数的好习惯吧,但是谁能解释一下这是为什么呢?  
  ---------------------------------------  
   
  给点提示:   howmany   h2=f(h);   这句,还有对象拷贝~呵呵  
  ps:lz不让偶说话,偶就不说了~:)Top

11 楼huangyangman(庸人自扰)回复于 2006-10-13 14:32:29 得分 0

哪有   哪有   开玩笑呢  
  确实是对象的逐位拷贝,所以没有调用constructor  
  Top

12 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:32:53 得分 0

唉,还是需要copy   constructor函数Top

13 楼huangyangman(庸人自扰)回复于 2006-10-13 14:34:20 得分 0

C++要维护C   还真是花了不少精力哦  
  感慨~~Top

14 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:35:55 得分 0

对象逐位copy时,static可不是逐位copyTop

15 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:36:47 得分 0

好例子啊。Top

16 楼Jokar(贪睡鼠)回复于 2006-10-13 14:38:11 得分 0

好例子啊。  
  ------------  
  是呀~蛮经典的~呵呵Top

17 楼huangyangman(庸人自扰)回复于 2006-10-13 14:39:37 得分 0

?   大鸟讲讲    
  最好来个高手把相关的知识总结一遍    
  让我好好学习下    
  Top

18 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:46:08 得分 0

鼠MM都憋半天了,让鼠MM讲吧。Top

19 楼hailongchang(什么时候才能看到星星啊。。。)回复于 2006-10-13 14:50:30 得分 0

鼠MM都憋半天了,让鼠MM讲吧。  
  ==================================  
   
  MM,怎么早没看出来?Top

20 楼huangyangman(庸人自扰)回复于 2006-10-13 14:53:21 得分 0

MM==妹妹?  
    Jokar(贪睡鼠★御姐控☆小宠王)        
        男人真命苦  
  ----------------  
  女人命苦的更多~呵呵  
      难怪说这句话    
  ____________________  
  顿悟!  
     
   
   
  Top

21 楼hailongchang(什么时候才能看到星星啊。。。)回复于 2006-10-13 14:54:30 得分 0

还是楼上看贴仔细啊Top

22 楼cwl_feng()回复于 2006-10-13 14:55:36 得分 0

这个程序运行在VS2003下会显示三次条用析构函数,一次是h的,一次是h2的。h2的算h拷贝过去,释放时条用析构函数,第三次是那个对象的?  
    莫非是x   形参的??  
   
  高手赶快冒个泡,解释一下Top

23 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 14:57:03 得分 0

按照BS的说法,如果t1和t2都是类T的对象,t1=t2的默认含义就是将t2按成员逐个复制到t1。对于包含了由构造函数/析构函数管理的资源的对象而言,按成员复制的语义通常是不正确的。  
  例:  
  viud   h()  
  {  
        T   t1;  
        T   t2=t1;  
        T   t3;  
        t3=t2;  
  }  
  默认构造函数被t1、t3各调用一次,一共两次。析构函数对t1、t2、t3各一次,一共3次。  
  lz的程序也是一样的。只是又转了一个弯,在f()函数的参数调用时,构造生成了局部对象,离开f()时析构。Top

24 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 15:03:31 得分 0

c++函数调用是值传递,也就是类似上面T   t2=t1那样生成了一个局部对象,没调默认构造函数,但离开函数时却调了析构函数。Top

25 楼weiym(磨刀霍霍向猪羊)回复于 2006-10-13 15:31:47 得分 0

类都有一个或多个构造函数,一个析构函数和一个赋值操作符,如果不提供就显示将他们定义成Private,可以减少好多类似问题Top

26 楼huangyangman(庸人自扰)回复于 2006-10-13 15:41:25 得分 0

可我正是提供了构造函数和析构函数啊Top

27 楼weiym(磨刀霍霍向猪羊)回复于 2006-10-13 15:52:35 得分 0

加个拷贝构造函数一切就都很明白了Top

28 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-13 16:05:00 得分 0

可我正是提供了构造函数和析构函数啊  
  ====================  
  呵呵,正是因为你有才出问题的。要是都没有,所有都是系统默认的,问题也没了。static变量也老实了(根本就不变)。你给它提供了一种构造函数,在拷贝构造时又没用你的构造函数,用了系统自己产生的构造函数,两种构造函数里对资源(把静态变量权且看作资源)处理不一致。更何况每个对象都会用到的那个析构函数里还设计资源处理。这里仅仅是静态变量,还不会出大错,要是用到指针,用到new,delete,呵呵~~~Top

29 楼huangyangman(庸人自扰)回复于 2006-10-13 16:12:25 得分 0

说错了   我要是写的出这么经典的例子就能教书育人了    
  应该说书上就是提供了构造函数和析构函数啊  
  这个例子本来就是用来引出copy   constructor的   闲来无事   抄了一段上来   呵呵  
   
  向前辈们学习.  
  再给我讲讲调用f()的时候stack   frame中是怎么分布的吧   比如说函数的参数,函数的地址,局部变量什么的   月多越好啊  
   
  Top

30 楼ugvihc(maybe good good study, hope day day up!)回复于 2006-10-13 16:19:16 得分 0

mark,   study...Top

31 楼anrui32(命令提示符(anrui32@163.com))回复于 2006-10-13 17:19:11 得分 0

做个标记,学习Top

32 楼zhulei5()回复于 2006-10-13 17:25:12 得分 0

接分吧Top

33 楼royeleo(煨灶猫||(只要一颗★))回复于 2006-10-13 17:26:50 得分 0

Mark  
  upTop

34 楼zephyr741(西风)回复于 2006-10-13 18:42:54 得分 10

#include   <fstream.h>  
   
  class   howmany{  
  static   int   object_count;  
  public:  
  howmany(){  
  object_count++;  
  }  
  static   void   print(const   char*   msg=0)  
  {  
  if(msg)   cout<<msg<<":";  
  cout<<"object_cout="  
  <<object_count<<endl;  
  }  
  ~howmany(){  
  object_count--;  
  print("~howmany()");  
  }  
  };  
  int   howmany::object_count=0;  
  howmany   f(howmany   x){   //这里调用了一次默认copy   constructor.  
  x.print("x   argument   inside   f()");  
  return   x;//又调用了一次copy   constructor.  
  }  
  void   main()   {  
  howmany   h;  
  howmany::print("after   construction   of   h");  
  howmany   h2=f(h);  
  howmany::print("after   call   to   f()");  
  }  
  copy   constructor   什么也不做。  
  所以上面的2次调用不会对object_count   产生任何影响,但是问题就来了,   constructor   之后再函数返回的时候堆栈上申请的那个临时的X会被调用destructor.  
  所以object_count--;  
  让我们从头开始   看看所有对象的情况  
  howmany   h;   //   constructor   object_count   ++;  
  howmany::print("after   construction   of   h");   //do   nothing   on   object_cout  
  howmany   h2=f(h);//   copy   constructor   do   nothing   注意这一句话里面有2次//copyconstructor.   其实还有一次copy   assign。不过没有影响,唯一有影响的是在函数返回//的时候调用destructor.   object_cout   --  
  howmany::print("after   call   to   f()");//nothing.  
  //这里会在调用两次destructor   分别destruct   h   和   h2  
   
  函数的调用方法,调用一个函数的时候会发生一系列的入栈操作,下面这一段是说明stdcall方式的,   pascal   和   cdecl   不太一样。  
  环境win32/vc6  
  比如有下面这样一个函数  
  void   f(   int   i,   int   j   ){   int   z;   }  
  //  
  然后调用按照下面这样  
  extern   int   i,   j;  
  int   res   =   f(   i   ,   j   );  
  转换为汇编的代码应该是下面这个样子  
  push   j;   参数j   进栈  
  push   i;   参数i   进栈  
  push   ebp;   ebp   进栈   ebp中存放的是前一个函数调用的ebp地址  
  mov   ebp,esp;   //   esp放进ebp中  
  sub   esp,4;   //   申请变量z    
  esp是stack-pointer   指向系统当前的堆栈栈顶,这个堆栈只在你自己的进程的地址空间中有效,注意有一点特别的:堆栈是从内存的高地址向低地址方向增长,所以入栈的操作会造成esp的减法操作,不是加法。  
  上面的前面两行称为函数的pre-prologue;   是操作参数的esp在这中间是有变化,esp   =   esp   -   8;  
  然后ebp进栈,ebp中保存的是前一个函数的堆栈桢的指针。  
  堆栈桢就是上面创建的这样一系列的参数包括返回地址还有函数上面申请的临时变量的一段内存空间。  
  但是ebp并不是指向这个桢的起始位置,而是在桢的中间,他们的内存结构应该是这样  
  高地址:       esp   ->   初始位置     参数j  
                                                        参数i  
                                                        ebp  
                                                        变量z  
  低地址:       esp   ->   终止位置   栈增长方向是从上往下。  
  所以几个变量的地址依次是     address   of   j   =   [ebp]   +   12;  
                                                      address   of   i   =   [ebp]   +   8;  
                                                      address   of   ebp   =   [ebp]   +   4;  
                                                      address   of   z   =   [ebp]   +   0;  
                                                      ....  
  注:   win32   中   int   是4个bytes;  
   
  貌似就这么多了,有不对的地方请大家指出,我会改正  
  另外:   推荐一个好网站:   www.codeproject.comTop

35 楼freshlifeO(微微)回复于 2006-10-13 20:02:41 得分 0

markTop

36 楼justrun2005(机枪)回复于 2006-10-16 00:58:54 得分 0

收藏Top

相关问题

关键词

得分解答快速导航

  • 帖主:huangyangman
  • Jokar
  • lann64
  • zephyr741

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo