C++ static 与 const
static
static定义的静态变量在函数执行后不会释放其存储空间,存储在内存的全局区域。static表示的是静态的。类的静态成员函数、静态成员变量是和类相关的,而不是和类的具体对象相关。即使没有具体对象,也能调用类的静态成员函数和成员变量。静态成员函数的访问权限是全局的,只要包含了声明它的头文件,都能调用它(public)。- 在 C++11 中,
static非constexpr的普通静态成员变量不能在类的内部初始化。在类的内部只是声明,必须在类外定义数据类型 类名::静态数据成员名=值;而静态成员函数定义无限制,调用时类名::静态成员函数名(参数表)。 - 从 C++17 起, 可用
inline关键词在类内定义内联静态数据成员,如inline static int a = 1,但多个定义必须完全相同。 static关键字只能用于类定义体内部的声明中,定义时不能标示为static。
Tip
static 成员函数主要用处是作为类作用域的全局函数。不能访问类的非静态数据成员。因为类的静态成员函数属于类本身,没有 this 指针,这导致:
- 不能直接存取类的非静态成员变量 或 调用非静态成员函数。
- 不能被声明为
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
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数据成员的值可以不同。要想建立在整个类中都恒定的常量,可以用类中的enum或static const或static constexpr。1
2
3
4
5
6
7
8
9
10
11
12class 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
10class 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
7class 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
7class Singleton{
public :
static Singleton Instance;//正确,静态成员自身类型,典型实现单例模式
Singleton _object;//错误,类对象会导致无限递归嵌套
Singleton *pInstance;//正确,指针
Singleton &mInstance;//正确,引用
};

