静态对象的探讨
类中静态成员变量
静态成员变量,需要先声明,然后再定义。如果没有使用到该静态成员变量,则可以不用定义。如果使用到了该静态成员变量,但是只做了声明,没有去定义,就会报链接错误。
namespace demo1 {
class A {
public:
A() {
m_i = 0;
std::cout << "A的构造函数被执行!" << std::endl;
}
~A() {
std::cout << "A的析构函数被执行!" << std::endl;
}
public:
int m_i;
};
class B {
public:
static A a; //声明
};
A B::a; //定义 一般是放在cpp文件里面
}
int main()
{
demo1::B b;
std::cout << "B::A::m_i:" << b.a.m_i << std::endl;
}
运行结果如下:
![](https://img.haomeiwen.com/i15040312/f4c6f2d4028f79ff.png)
注意:类中的类类型静态成员变量,如果定义了,但是没有使用,依旧会生为该成员变量分配内存空间(构造)。
如果静态成员变量不是类类型,是基本类型(int, float...),且源码中没有用到过这个静态成员变量,编译器很可能不为该变量分配内存。
c++17中引用了inline关键字,可以将静态成员变量的声明和定义同时处理,即不用再cpp中对静态成员变量进行定义。
inline static A a; //声明 + 定义
函数中静态对象
如果函数没有被调用过,则静态对象就不会被构造,即使函数被调用多次,该对象也只会被构造一次。整个程序退出时,才被析构。
namespace demo1 {
class A {
public:
A() {
m_i = 0;
std::cout << "A的构造函数被执行!" << std::endl;
}
~A() {
std::cout << "A的析构函数被执行!" << std::endl;
}
public:
int m_i;
};
void myFunc()
{
static A a;
}
}
int main()
{
demo1::myFunc();
demo1::myFunc();
demo1::myFunc();
}
运行结果如下:
![](https://img.haomeiwen.com/i15040312/b1b80fdf367126ea.png)
从运行结果可以看出,myFunc调用三次,函数中的静态对象,只被构造一次。
全局对象的构造顺序
如果一个项目中有多个.cpp源文件,每个源文件可能定义一些不同的全局对象,那么,这些全局对象的构造顺序是无规律的。
千万不能在构造一个全局对象的时候(构造函数),使用另外一个全局对象,因为无法确定该对象是否已经构造出来。
如果确实需在一个全局对象的构造函数中使用另外一个全局对象,可以用全局函数来处理。
//全局函数
class ClassB;
ClassB& GetClassB()
{
static ClassB b; //如果c++11 多线程调用时,该行不安全,最好在主线程中进行调用该函数进行构造
return b;
}
ClassA::ClassA()
{
std::cout << "ClassB::m_i"<< GetClassB().m_i << std::endl;
}
另外也不要在一个全局对象的析构函数中调用其他全局对象,因为无法确定该对象是否已经析构。
函数中静态对象的构造顺序
函数中静态对象的构造顺序,就是第一次运行到该处时,进行构造。
类中静态对象的构造顺序
同一个编译单元(即同一个cpp),静态成员对象的构造顺序,跟定义的顺序有关,与声明顺序无关。
网友评论