static

  • static 定义的静态变量在函数执行后不会释放其存储空间,存储在内存的全局区域。
  • static 表示的是静态的。类的静态成员函数、静态成员变量是和相关的,而不是和类的具体对象相关。即使没有具体对象,也能调用类的静态成员函数和成员变量。静态成员函数的访问权限是全局的,只要包含了声明它的头文件,都能调用它(public)。
  • 在 C++11 中,staticconstexpr 的普通静态成员变量不能在类的内部初始化。在类的内部只是声明,必须在类外定义 数据类型 类名::静态数据成员名=值 ;而静态成员函数定义无限制,调用时 类名::静态成员函数名(参数表)
  • 从 C++17 起, 可用 inline 关键词在类内定义内联静态数据成员,如 inline static int a = 1 ,但多个定义必须完全相同。
  • static 关键字只能用于类定义体内部的声明中,定义时不能标示为 static

Tip

static 成员函数主要用处是作为类作用域的全局函数。不能访问类的非静态数据成员。因为类的静态成员函数属于类本身,没有 this 指针,这导致:

  1. 不能直接存取类的非静态成员变量 或 调用非静态成员函数。
  2. 不能被声明为 virtual。因为虚函数的实现依赖 vtable(虚函数表) 和对象实例的 vptr(指向 vtable 的指针),而静态成员函数没有 this,因此没有办法通过对象的多态机制调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

class Test {
int value; // 非静态成员变量
static int staticValue; // 静态成员变量

public:
Test(int v) : value(v) {}

void normalFunc() { // 普通成员函数
cout << "normalFunc(): value = " << value << endl;
}

static void staticFunc() { // 静态成员函数
cout << "staticFunc(): staticValue = " << staticValue << endl;

// ❌ 不能访问非静态成员变量
// cout << value; // 编译错误:没有 this 指针

// ❌ 不能直接调用非静态成员函数
// normalFunc(); // 编译错误:没有 this 指针
}
};

int Test::staticValue = 42; // 静态成员变量需要类外定义

int main() {
Test t(10);

// 普通成员函数调用
t.normalFunc(); // ✅ 输出 value = 10

// 静态成员函数调用(两种方式)
Test::staticFunc(); // ✅ 推荐用类名调用,输出 staticValue = 42
t.staticFunc(); // ✅ 虽然能用对象调用,但本质上跟类名调用一样

return 0;
}


const

  • 从 C++11 起,const 成员变量支持类内定义赋初值,也可通过构造函数列表初始化(优先级高)。
  • const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其 const 数据成员的值可以不同。要想建立在整个类中都恒定的常量,可以用类中的 enumstatic conststatic constexpr
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Test{
    public:
    Test(): a{false} {} //被列表初始化覆盖
    enum { size1 = 100, size2 = 200 };
    private:
    const bool a = true;
    static int b; //类内声明
    const static int c; //与 static const int c;相同
    };

    int Test::b = 0; //类外定义,static 成员变量不能在构造函数初始化列表中初始化,因为它不属于某个对象
    const int Test::c = 0; //注意:不需要加 static 修饰符,但要加 const

Tip

const 成员函数不能修改成员变量的值(非 mutable ),但可以读取。对于只用于访问数据而不修改数据的成员函数,应声明为 const 成员函数,常量对象才能调用它。因为如果一个对象被声明为 const,那它只能调用 const 成员函数。

1
2
3
4
5
6
7
8
9
10
class A {
int x;
public:
int getX() const { return x; }
void setX(int v) { x = v; } // 会修改成员变量,不是 const
};

const A a; //常量对象
a.getX(); // OK,因为 getX 是 const
a.setX(5); // ❌ 编译错误,因为 setX 不是 const


其他

  • 静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。举例如下:
    1
    2
    3
    4
    5
    6
    7
    class base{ 
    public :
    static int _staticVar;
    int _var;
    void foo1(int i = _staticVar);//正确,_staticVar为静态数据成员
    void foo2(int i = _var);//错误,_var为普通数据成员
    };
  • 静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为所属类类型的指针或引用。举例如下:
    1
    2
    3
    4
    5
    6
    7
    class Singleton{ 
    public :
    static Singleton Instance;//正确,静态成员自身类型,典型实现单例模式
    Singleton _object;//错误,类对象会导致无限递归嵌套
    Singleton *pInstance;//正确,指针
    Singleton &mInstance;//正确,引用
    };