全局变量,局部静态变量初始化以及类静态成员变量初始化

时间:2023-01-12 19:38:09

全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。

class B{
public:
B()
{
cout << "B constructor called" << endl;
}
~B()
{
cout << "B desconstructor called" << endl;
}
};
class A{
public:
A()
{
cout << "A constructor called" << endl;
}
~A()
{
cout << "A desconstructor called" << endl;
}
private:
static B b;
};

class C{
public:
C()
{
cout << "C constructor called" << endl;
}
~C()
{
cout << "C desconstructor called" << endl;
}
};
class D{
public:
D()
{
cout << "D constructor called" << endl;
}
~D()
{
cout << "D desconstructor called" << endl;
}
};
class E{
public:
E()
{
cout << "E constructor called" << endl;
}
~E()
{
cout << "E desconstructor called" << endl;
}
};
int f()
{
system("pause");
return 0;
}
C c;
static E e;
B A::b = B();//静态成员变量在类外初始化
int main()
{
_onexit(f);
A *pa = new A;
B b;
static D d;
delete pa;
return 0;
}
输出:

C constructor called//全局变量初始化在main执行之前
E constructor called//全局静态变量初始化在main之前

B constructor called//类中的静态成员变量在类外初始化在main之前

A constructor called//main中执行A的默认构造函数,但是没有调用B的默认构造函数,(若A中的成员变量b不是static型的,那么在调用A的构造函数                                                                                                             时,系统会调用B的默认构造函数,这里涉及到构造函数成员初始化列表的作用)

B constructor called//构造b

D constructor called//局部静态变量在第一次使用时初始化

A desconstructor called//显示调用A的析构

B desconstructor called//局部变量在栈上,早析构

D desconstructor called//局部静态变量出了main后析构

B desconstructor called//类的静态成员变量析构

E desconstructor called//全局静态变量析构

C desconstructor called//全局变量析构,这后边三个析构顺序,应该和它们的构造顺序相反!!!!

下边内容转载:

有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同。这些特殊的类型的成员变量包括:

a.引用

b.常量

c.静态

d.静态常量(整型)

e.静态常量(非整型)

常量和引用,必须通过参数列表进行初始化。这里不包括常量静态成员变量,因为无法通过构造函数初始化静态类数据。但是非常量静态类数据,可以通过构造函数体赋值。

例如:

class Test {
public:
int a;
static int b;
public:
Test(int _a, int _b) : a(_a){
b = _b;
}
};
int Test::b;
int main() {
Test t1(0, 0), t2(1, 1);
t1.b = 10;
t2.b = 20;
printf("%u %u %u %u", t1.a, t1.b, t2.a, t2.b);
system("pause");
return 0;
}
但如果是常量静态类数据就不行了,因为不能对常量赋值。

静态成员变量的初始化也颇有点特别,是在类外初始化且不能再带有static关键字,记住是类外初始化,但可以在构造函数中赋值 ,其本质见文末。

参考下面的代码以及其中注释:

    #include   
using namespace std;

class BClass
{
public:
BClass() : i(1), ci(2), ri(i){} // 对于常量型成员变量和引用型成员变量,必须通过参数化列表的方式进行初始化
//普通成员变量也可以放在函数体里,但是本质其实已不是初始化,而是一种普通的运算操作-->赋值运算,效率也低
private:
int i; // 普通成员变量
const int ci; // 常量成员变量
int &ri; // 引用成员变量
static int si; // 静态成员变量
//static int si2 = 100; // error: 只有静态常量成员变量,才可以这样初始化
static const int csi; // 静态常量成员变量
static const int csi2 = 100; // 静态常量成员变量的初始化(Integral type) (1)
static const double csd; // 静态常量成员变量(non-Integral type)
//static const double csd2 = 99.9; // error: 只有静态常量整型数据成员才可以在类中初始化
};

//注意下面三行:不能再带有static
int BClass::si = 0; // 静态成员变量的初始化(Integral type)
const int BClass::csi = 1; // 静态常量成员变量的初始化(Integral type)
const double BClass::csd = 99.9; // 静态常量成员变量的初始化(non-Integral type
静态成员属于类作用域,但不属于类对象,和普通的static变量一样,程序一运行就分配内存并初始化,生命周期和程序一致。
所以,在类的构造函数里初始化static变量显然是不合理的。
静态成员其实和全局变量地位是一样的,只不过编译器把它的使用限制在类作用域内(不是类对象,它不属于类对象成员),要在类的定义外(不是类作用域外)初始化。

下面再说说成员变量是引用的情况:

因为引用是别名的意思,所以定义应用肯定是外部有定义,然后在构造函数初始化列表中被初始化的。

如果两个类要对第三个类的数据进行共享处理,可以考虑把第三个类作为这两个类的引用类型的成员变量。