关于为什么类的静态成员变量不能立即初始化 .

    我们都知道代码1是错误的,今天我去追究其原因。当然有些地方属于个人理解,有所纰漏,请不吝惜指正。

 // test.h

[c-sharp] view plain copy print ?
  1. class Test {  
  2. public:  
  3.     static int a = 5;  
  4. };  

                                                  代码1

 

      当我们写下面的代码时,而没有在cpp文件里给出定义,就会出现无法解析的外部符号错误。这是因为"static int a;"是对变量a的声明。我们都知道,类实例化时,编译器分配内存给成员变量,也就是说,当产生类的实例时定义成员变量,但是对于静态成员变量呢?

[c-sharp] view plain copy print ?
  1. //  test.h   
  2. class Test {  
  3. public:  
  4.     static int a;  
  5. };  

                                                  代码2

     

      我们假设静态成员变量和其他成员变量没有区别,也是在类实例化时编译器赋予内存,那么如下代码:

 

  1. // farm1.cpp   
  2. #include "test.h"   
  3.   
  4. void fun() {  
  5.     Test t;  
  6.     t.a = 3;  
  7. }  

                                                  代码3

 

就定义了一个局部对象,那么自然而然的,当这个函数执行完毕的时候,对象t析构,静态成员变量a的空间被释放掉。那就根本无法达到类共享静态成员变量的目的。所以有如下结论:静态成员变量在类实例化之前就已经存在了,并且分配了内存,它交由类专属使用(这是靠static的内部链接属性实现的),类无法控制它何时被分配内存,何时释放。我们不妨把它理解为一个在类中声明,专属于类的全局变量,它的链接属性为内部链接。

 

      谈完静态成员变量的性质以后,让我们来讨论一下为什么静态成员变量不能立即初始化,也就是像代码1那样去做。

      假设我们可以将静态成员变量立即初始化,那么代码3展开:

[c-sharp] view plain copy print ?
  1. // farm1.cpp   
  2.   
  3. class Test {  
  4. public:  
  5.    static int a = 0;  
  6. }  
  7.   
  8. void fun() {  
  9.    Test t;  
  10.    t.a = 3;  
  11. }  

这里面的静态成员变量不再是一个声明,而是定义,当函数fun执行到"t.a = 3;"时,不会再把a当成为一个外部符号,不会把它放入未解决符号表中。a首先被赋值为0,然后被修改为3。再看以下代码:

  1. // farm2.cpp   
  2. #include "test.h"   
  3.   
  4. void fun() {  
  5.    Test t;  
  6.    t.a += 3;  
  7. }  
  8.   
  9. 展开后:  
  10. // farm2.cpp   
  11.   
  12. class Test {  
  13. public:  
  14.    static int a = 0;  
  15. };  
  16.   
  17. void fun() {  
  18.    Test t;  
  19.    t.a += 3;  
  20. }  

这里面是同样的道理,"static int a = 0;"不再是一个声明,而是定义,当函数fun执行到"t.a += 3;"时,不会把a当成一个外部符号,不会把它放入未解决符号表中。所以在本编译单元里寻找t.a,发现值为0,那么"t.a += 3;"的执行结果是t.a的值为3,而不是6,没有类的对象共享静态成员变量的目的。

 

     有人可能会问为什么"const static int a = 5;"这样的语句放在类的定义里可以呢,如下面代码:

[c-sharp] view plain copy print ?
  1. // test.h   
  2. class Test {  
  3. public:  
  4.     const static int a = 5;  
  5. }  

那是因为const使其成为了常量,不会担心上面所述的问题。但是,这样的定义,虽然值是不会改变,会不会造成无法共享静态成员变量a呢?因为在包含该类的头文件的cpp里面,将#include "test.h"扩展后,都有这么一句"const int a = 5;"这岂不是在不同的地方定义了静态成员变量a么?也就是说,当我们要取a的地址的时候,会不会发现在包含test.h的各个cpp中,取得a的地址不同?

     请看下面代码:

  1. #include "test.h"   
  2.   
  3. void Farm1::test()  
  4. {  
  5.     Test t;  
  6.     int b = t.a;  
  7. }  

该段代码经过反汇编后:

  1. void Farm2::test()  
  2. {  
  3. 00411410  push        ebp    
  4. 00411411  mov         ebp,esp   
  5. 00411413  sub         esp,0E8h   
  6. 00411419  push        ebx    
  7. 0041141A  push        esi    
  8. 0041141B  push        edi    
  9. 0041141C  push        ecx    
  10. 0041141D  lea         edi,[ebp-0E8h]   
  11. 00411423  mov         ecx,3Ah   
  12. 00411428  mov         eax,0CCCCCCCCh   
  13. 0041142D  rep stos    dword ptr es:[edi]   
  14. 0041142F  pop         ecx    
  15. 00411430  mov         dword ptr [ebp-8],ecx   
  16.     Test t;  
  17.     int b = t.a;  
  18. 00411433  mov         dword ptr [b],5   
  19. }  

可以看到int b = t.a;的汇编语句是:

00411433  mov         dword ptr [b],5

这说明编译器已经对const int static a = 5;优化了。注意:只有静态常量整形数据成员才可以立即初始化。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值