静态成员和临时对象

本文通过代码示例分析C++中静态成员变量human_num在涉及临时对象时的不当行为,强调默认复制构造函数未处理静态成员可能导致错误计数。临时对象主要在值传递和返回值时产生,可通过引用传递避免。文中还提供了修改后的代码以正确计算实例数。
摘要由CSDN通过智能技术生成

一、看代码写结果——c++静态成员和临时对象

[cpp]  view plain  copy
  1. <span style="font-size:18px;">#include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class human  
  6. {  
  7. public:  
  8.     human()  
  9.     {  
  10.         human_num++;  
  11.     }  
  12.     static int human_num;  
  13.     ~human()  
  14.     {  
  15.         human_num--;  
  16.         print();  
  17.     }  
  18.     void print()  
  19.     {  
  20.         cout<<"human num is: "<<human_num<<endl;  
  21.     }  
  22. };  
  23.   
  24. int human::human_num = 0;  
  25.   
  26. human f1(human x)  
  27. {  
  28.     x.print();  
  29.     return x;  
  30. }  
  31.   
  32. int main()  
  33. {  
  34.     human h1;  
  35.     h1.print();  
  36.     human h2 = f1(h1);  
  37.     h2.print();  
  38.       
  39.     return 0;  
  40. }</span>  
解析:

  这个程序的human类有一个静态成员human_num,每执行一次普通的构造函数human_num加1,每指向一次析构函数,human_num减1。注意,在f1()函数中会使用默认的复制构造函数,而默认的复制构造函数没有对human_num处理。

  代码第34行,只构造了对象h1(调用普通构造函数),因此打印1。

  代码第35行,使用值传递参数的方式调用了f1()函数,这里分为3步;

  (1)在f1函数内首先会调用复制构造函数生成一个临时对象,因此代码第27行打印1。

  (2)f1函数内调用复制构造函数,给main的对象h2初始化(复制临时对象)

  (3)f1函数返回后,临时对象发生析构,此时human的静态成员human为0,打印出0。

  代码第36行打印的还是0。

  main函数结束时有h1和h2两个对象要发生析构,所以分别打印出-1和-2。

  程序的意图很明显,就是静态成员用human_num记录类human的实例数。然而,由于默认的复制构造函数没有对静态成员操作,导致了执行结果的不正确。这里可以通过添加一个自定义的复制构造函数解决。

[cpp]  view plain  copy
  1. human(human& h)  
  2. {  
  3.     human_num++;  
  4. }  
此时human_num就能起到应有的作用了。

执行结果:

[cpp]  view plain  copy
  1. human num is: 1  
  2. human num is: 1  
  3. human num is: 0  
  4. human num is: 0  
  5. human num is: -1  
  6. human num is: -2  

二、什么是临时对象?临时对象在什么情况下产生?

  当程序员之间进行交谈时,经常把仅仅需要一小段时间的变量称为临时变量。例如在下面的swap函数里:

[cpp]  view plain  copy
  1. void swap(int &a, int &b)  
  2. {  
  3.     int temp = a;  
  4.     a = b;  
  5.     b = temp;  
  6. }  
  通常称temp为临时变量。但在c++里,temp根本不是临时变量。实际上,他只是一个函数的局部变量。

  真正的临时对象时看不见的,他不会出现在程序代码中。大多数情况下,他会影响程序执行的效率,所以有时想避免临时对象的产生。它通常在一下两种情况下产生。

(1)参数按值传递。

(2)返回值按值传递。

参考下面代码:

[cpp]  view plain  copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class Test  
  6. {  
  7.     int num;  
  8. public:  
  9.     Test() : num(0) { }                     //默认构造函数  
  10.     Test(int number) : num(number) { }      //带参数的构造函数  
  11.     void print()                            //打印私有成员num  
  12.     {  
  13.         cout<<"num = "<<num<<endl;  
  14.     }  
  15.     ~Test()  
  16.     {  
  17.         cout<<"destructor: this = "<<this<<",num = "<<num<<endl;  
  18.     }  
  19. };  
  20.   
  21. Test fun1(Test test)                        //参数按值传递  
  22. {  
  23.     test.print();  
  24. }  
  25.   
  26. void fun2()                                 //返回值按值传递  
  27. {  
  28.     Test t(3);  
  29.     return t;  
  30. }  
  31.   
  32. int main()  
  33. {  
  34.     Test t1(1);  
  35.     fun1(t1);                               //对象传入  
  36.     fun1(2);                                //整型数2传入  
  37.     t1 = fun2();  
  38.       
  39.     return 0;  
  40. }  
  程序中fun1()参数是按值传递的,fun2函数的返回值是按值传递的。在Test类的析构函数中打印了this指针的值,下面是执行结果:

[cpp]  view plain  copy
  1. num = 1  
  2. destructor: this = 0xbffb2b84,num = 1     (fun1内的临时对象析构)  
  3. num = 2  
  4. destructor: this = 0xbffb2b88,num = 2     (fun1内的临时对象析构)  
  5. destructor: this = 0xbffb2b8c,num = 3     (fun2内返回的临时对象析构)  
  6. destructor: this = 0xbffb2b80,num = 3     (main内的t1析构)  
  这里代码第35,36行使用了两种类型参数传入fun1函数。它们都会生成临时变量,不同点是采用不同的方式:第35行的调用使用了复制构造函数创建临时变量,而第36行调用了带参数的构造函数创建临时变量。

  如何避免临时变量的产生呢?可以使用引用传递代替值传递。这样就不会产生临时对象了。

0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值