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

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

// test.h

class Test {

public:

static int a = 5;

};

代码1

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

//  test.h

class Test {

public:

static int a;

};

代码2

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

// farm1.cpp

#include "test.h"

void fun() {

Test t;

t.a = 3;

}

代码3

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

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

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

// farm1.cpp

class Test {

public:

static int a = 0;

}

void fun() {

Test t;

t.a = 3;

}

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

// farm2.cpp

#include "test.h"

void fun() {

Test t;

t.a += 3;

}

展开后:

// farm2.cpp

class Test {

public:

static int a = 0;

};

void fun() {

Test t;

t.a += 3;

}

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

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

// test.h

class Test {

public:

const static int a = 5;

}

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

请看下面代码:

#include "test.h"

void Farm1::test()

{

Test t;

int b = t.a;

}

该段代码经过反汇编后:

void Farm2::test()

{

00411410  push        ebp

00411411  mov         ebp,esp

00411413  sub         esp,0E8h

00411419  push        ebx

0041141A  push        esi

0041141B  push        edi

0041141C  push        ecx

0041141D  lea         edi,[ebp-0E8h]

00411423  mov         ecx,3Ah

00411428  mov         eax,0CCCCCCCCh

0041142D  rep stos    dword ptr es:[edi]

0041142F  pop         ecx

00411430  mov         dword ptr [ebp-8],ecx

Test t;

int b = t.a;

00411433  mov         dword ptr [b],5

}

可以看到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、付费专栏及课程。

余额充值