前言
类的静态成员有成员对象以及成员函数, 之所以将静态成员单独提出来, 就是因为它的特别, 静态成员对象并不在类的内存分布中, 而是在ELF中的.data
段中, 是该类的每个实例化共享的资源; 同样静态成员函数也类似与普通函数, 函数体内只能直接操作静态成员对象.
静态成员对象
static
成员对象是存储在data
段中, 并不是直接存放在类中, 所以不能通过this
访问到静态成员对象, 并且需要在类外执行初始化. 因为static
成员变量是在程序编译时初始化并保存在data
中, 不是类实例化才出初始化, 这也证实类的每个实例化都只有一个实例化的static
成员对象.
同样可以直接使用类本身直接去访问静态成员对象, 不需要实例化对象去访问, 主要就是它早已被实例化了.
class A {public: static int x;}; int A::x = 0;
A::x; // 直接访问
当然可以用static
成员对象在构造函数中去初始化在其他的成员变量.
class A {
public:
A() : y(x) {} // 可用于初始化其他非静态成员对象
private: static int x; int y;
};
int A::x = 0;
非静态成员对象
对于非static
成员对象在类中分布我们在前面几节中已经分析过了, 这里做一个小结 : 对非static
成员, 获取的地址是内存中对象**this
指向的成员对象的地址 + 1 ** , 因为第一个地址存放的是vptr
的地址, 所以其他的地址就要源地址 + 1.
同时非static
成员对象必须在类被实例化时才会被初始化, 被调用, 并且在类中使用时默认时由this
指针指向.
静态成员函数
static
成员函数 : 像是外部函数, 它并不能直接调用非static
成员变量 , 即静态函数只能调用静态变量, 调用其他的类成员变量会报错.
原因 : 静态成员函数就像外部定义的函数一样, 同时也与静态成员变量一样,可以直接通过Static_Function::fun()
, 也就是不用实例化类对象就可以直接调用静态函数. 但是对于非静态成员对象需要在类被实例化时才被创建. 那么直接调用静态成员函数并不能保证非静态成员对象已经被实例化了, 如果没有被实例化编译器就会调用一个不存在的对象, 为了安全, 所以不允许有非静态成员.
class Static_Function
{
public:
static int g ;
int l = 0;
static void fun()
{
l = 1; // error. 不能调用非static成员, 因为 l 变量不能保证存在
g = 0;
}
};
int Static_Function::g = 0;
Static_Function::fun();
总结
在使用静态成员时要清楚他们的生命周期是到程序结束, 并且要清楚他们是保存在.data
段由该类的每个实例化对象共享的; 而静态成员函数只能调用静态成员对象.