C++ 面向对象_1

C++ 静态数据

在 C++ 中,静态数据(Static Data)是指使用 static 关键字修饰的数据,其生命周期与程序的整个运行时相同,而不是局限于某个作用域。静态数据在程序启动时分配内存,在程序结束时释放。与普通的局部变量或动态分配的变量不同,静态数据的生存期是全局的,但其作用域可以是局部的或全局的。

静态数据可以出现的场景:

  1. 全局/命名空间作用域中的静态变量:在文件级别定义的静态变量,只在定义它的文件中可见。
  2. 函数中的静态局部变量:在函数内部定义,只初始化一次,且在函数调用之时保持其作用域。
  3. 类的静态数据成员:属于类本身,而不是类的某个对象,所有对象共享同一份数据。

如何使用静态数据?

C++ 中的静态数据的定义和使用方式包括:

  1. 全局静态变量

    static int globalStaticVar = 10; // 只在当前文件中可见
    

    使用 static 修饰全局变量,限制其作用域为当前文件。
    常用于模块化编程,避免与其他文件的同名变量冲突。

  2. 函数中的静态局部变量

    void counter() {
        static int count = 0; // 只初始化一次
        count++;
        std::cout << "Count: " << count << std::endl;
    }
    
    int main() {
        counter(); // 输出: Count: 1
        counter(); // 输出: Count: 2
        counter(); // 输出: Count: 3
        return 0;
    }
    

    函数中的静态变量在函数第一次调用时初始化为0,后续调用不会重新初始化,并且保留之前值,可以看到 count。

  3. 类的静态数据成员

    class MyClass {
    public:
        static int staticMember; // 声明静态数据成员
    };
    
    // 在类外定义并初始化
    int MyClass::staticMember = 100;
    
    int main() {
        MyClass obj1, obj2;
        obj1.staticMember = 200; // 修改静态成员
        std::cout << obj2.staticMember << std::endl; // 输出: 200
        std::cout << MyClass::staticMember << std::endl; // 输出: 200
        return 0;
    }
    

    静态数据成员必须在类外定义并初始化。所有对象共享同一份 staticMember,可以通过对象或类名访问。

静态数据的定义方式

  1. 全局静态变量:static 类型 变量名;
  2. 函数内静态变量:在函数内使用 static 类型 变量名;
  3. 类静态数据成员:
    • 在类中声明:static 类型 变量名;
    • 在类外定义:类型 类名::变量名 = 初始值;

静态数据成员的访问方式

  1. 通过类名访问:类名::静态成员名(推荐方式)。
  2. 通过对象访问:对象名.静态成员名(不推荐,因为容易让人误以为是对象的成员)。

从内存层面理解静态数据

在内存中,静态数据存储在程序的数据段(Data Segment) 中。具体在数据段的什么位置:

已初始化数据段(.data):存储已初始化的全局变量和静态变量。
未初始化数据段(.bss):存储未初始化的全局变量和静态变量(默认初始化为 0)。

例如:

static int a = 10; // .data 段
static int b;      // .bss 段

在编译阶段由编译器识别到 static 关键字,将标识符标记为静态存储,并在符号表中记录条目,并在最后的目标文件中标记其存储的位置,程序在完成最后的链接操作后就为静态数据分配内存布局。

对于函数中的静态局部变量,编译器会将其存储在数据段,并在第一次执行到定义时进行初始化,如果编译器进行优化会在编译阶段就进行初始化。

类中的静态数据

静态数据成员是类的一个特殊成员,它被类的所有对象共享,而不是每个对象都拥有自己的副本。这意味着无论创建多少个类的实例,静态数据成员在内存中只存在一份。

在 C++98 中,静态数据成员通常需要在类内声明,在类外定义并初始化

class MyClass {
public:
    static int count;           // 类内声明
    static const int VALUE = 10; // const 静态成员可以在类内初始化
};

int MyClass::count = 0;  // 类外定义并初始化非const静态成员

C++98 标准允许 const 静态成员在类内初始化。

C++17 引入内联静态成员变量,允许在类内直接初始化非 const 静态成员:

class MyClass {
public:
    inline static int count = 0;        // 类内直接初始化
    inline static std::string name = "Class"; // 复杂类型也可以
};

在类的内部声明相同类型的静态数据成员

类可以包含与自身类型相同的静态成员,这在实现设计模式如单例模式时很有用:

class Node {
private:
    int data;
    Node* next;
    
    // 静态成员,类型为 Node*
    static Node* head;
    static Node* tail;
    
public:
    Node(int val) : data(val), next(nullptr) {}
    
    static void add(int val) {
        Node* newNode = new Node(val);
        if (!head) {
            head = tail = newNode;
        } else {
            tail->next = newNode;
            tail = newNode;
        }
    }
};

// 类外定义
Node* Node::head = nullptr;
Node* Node::tail = nullptr;