C++ 学习笔记 静态成员与常成员
一,static 静态成员
在类定义中,关键词static声明不绑定到类实例的成员
在类外定义,它有不同含义
1.声明静态数据成员
类的静态成员不与类的对象关联:他们时具有静态存储期的独立变量,或者常规函数
static关键词仅与静态成员在类定义中声明一同使用,但不与该静态成员的定义一同使用(使用时不用static关键词)
静态数据成员不能为mutable.
类体内的声明不是定义,且可以将成员声明为具有不完整类型,包括该成员的声明所在的类型:
C++11 使用constexpr 或c++17 inline说明符,声明时,则必须声明该成员为具有完整类型。
1 struct Foo; 2 struct S 3 { 4 static int a[]; // 声明,不完整类型 5 static Foo x; // 声明,不完整类型 6 static S s; // 声明,不完整类型(在其自身定义中) 7 }; 8 9 int S::a[10]; // 定义,完整类型 10 struct Foo {}; 11 Foo S::x; // 定义,完整类型 12 S S::s; // 定义,完整类型
可用两种形式来指代类T的静态成员限定名T::m,或成员访问表达式E.m或E->m,其中E分别时求值为T或T*的表达式。在同一类作用域,限定时不必要的:
1 struct X 2 { 3 static void f(); // 声明 4 static int n; // 声明 5 }; 6 7 X g() { return X(); } // 某个返回 X 的函数 8 9 void f() 10 { 11 X::f(); // X::f 是静态成员函数的限定名 12 g().f(); // g().f 是指代静态成员函数的成员访问表达式 13 } 14 15 int X::n = 7; // 定义 16 17 void X::f() // 定义 18 { 19 n = 1; // X::n 在此作用域可以仅以 n 进行访问 20 }
2,常量静态成员
若整型或枚举型的静态数据成员被声明为const(且volatile),则它能以其中的每个表达式为常量表达式的初始化器,直接在类定义内初始化
1 struct X { 2 static const int n = 1; 3 static constexpr int m = 4; 4 }; 5 const int *p = &X::n, *q = &X::m; // X::n 与 X::m 被 ODR 式使用 6 const int X::n, X::m; // ……故需要定义 7 constexpr int X::m; // (但 C++17 中的 X::m 不需要)
3,声明静态成员函数
1)静态成员函数不关联任何对象,调用时,他们无this指针。
2)静态成员函数不能为virtual, const或volatile
3)静态成员函数的地址可以存储在常规的函数指针中,但不能存储与成员函数指针中;
二,const 常量成员
C++ 类型系统中有另外三个独立的类型:const-限定的 T
、volatile-限定的 T
及 const-volatile-限定的 T
。
- const 对象——类型为 const-限定的 对象,或 const 对象的非 mutable 子对象。这种对象不能修改:尝试直接这么做是编译时错误,而尝试间接这么做(例如通过到非 const 类型的引用或指针修改 const 对象)导致未定义行为。
- volatile 对象——类型为 volatile-限定的 对象,或 volatile 对象的子对象,或 const volatile 对象的 mutable 子对象。通过 volatile 限定的类型的泛左值表达式的每次访问(读或写操作、成员函数调用等),都被当作对于优化而言是可见的副作用(即在单个执行线程内,volatile 访问不能被优化掉,或者与另一按顺序早于或按顺序晚于该 volatile 访问的可见副作用进行重排序。这使得 volatile 对象适用于与信号处理函数之间的交流,但不适于与另一执行线程交流)。试图通过非 volatile 泛左值涉指 volatile 对象(例如,通过到非 volatile 类型的引用或指针)会导致未定义行为。
- const volatile 对象——类型为 const-volatile-限定的 对象,const volatile 对象的非 mutable 子对象,volatile 对象的 const 子对象,或 const 对象的非 mutable volatile 子对象。同时表现为 const 对象与 volatile 对象。
mutable说明符-容许在即便包含它的对象被声明为 const 时仍可修改声明为 mutable 的类成员。
mutable 用于指定不影响类的外部可观察状态的成员(通常用于互斥体、记忆缓存、惰性求值和访问指令等)。