Last Updated: 2023-12-25 07:47:28 Monday
-- TOC --
在C++的类定义中(class/struct),可以存在对成员变量或函数的static申明,它们被称为static member,其含义与C中的static大同小异。
C++把那些从C开始就有的所谓的fundamental types也看做object,另一个runtime概念是object life cycle。C语言中的全局变量,局部变量,static变量,统统都放在object life cycle这个范畴下,在C++中进行重新的理解,其实就是这些变量的memory什么时候申请,什么时候释放。
static表示对象的storage
不是动态的,而是静态的,即在程序开始时allocate,在程序退出时才deallocate。static申明出现的位置,决定了其可被访问的scope。
static变量不与对象绑定,运行时只有一个副本,存放在.data区域。
Static members are members of a class that aren’t associated with a particular instance of the class. Normal class members have lifetimes nested within the class’s lifetime, but static members have
static storage duration
. These members are essentially similar to static variables and functions declared at global scope; however, you must refer to them by the containing class’s name, using the scope resolution operator::
. In fact, you must initialize static members at global scope. You cannot initialize a static member within a containing class definition.
普通成员变量因为多个类对象的实例化,会存在多个不同的副本,其生命周期与对象生命周期相同。而static变量不与对象绑定,在没有将类实例化的时候,它也存在那里,只是不一定能够被代码访问。运行时不管实例化了多少个对象,static成员变量都只有一份,它一直在那里,静静地待着。
类中的静态成员变量必须在类中声明,在类外定义(被const修饰的除外),这似乎是ISO C++的一个硬性规定,如果在申明时直接赋初值,会看到如下错误提示:
error: ISO C++ forbids in-class initialization of non-const static member
static变量必须在class外面做初始化,否则后面的代码无法引用它:
#include <iostream>
using namespace std;
struct xyz {
int a;
int b;
static int c;
int d;
xyz(int a, int b, int d): a{a},b{b},d{d} {}
};
int xyz::c {3};
int main(void){
xyz x{1,2,4};
cout << x.a << x.b << xyz::c << x.d << endl;
return 0;
}
输出:1234
注意:
int xyz::c;
,不初始化,运行起始其值必为0。还记得C语言中关于变量初始化的知识吗?
编译器会保证没有初始化的全局变量和静态变量,在程序加载的时候,全部初始化为0,并且,这些没有初始化的全局和静态变量,不占用.data section的空间,只是在bss段有个记录,这可以有效减小程序文件的size。
一般定义都在头文件中,如果被多个代码文件引用,static成员如果赋初值,就是重复定义了。这种被多个代码文件引用的情况,就必须要选择一个代码文件,来给static成员做初始化。如下代码示例:
// a header file:
struct OtherType {
static int classCounter;
// ...
};
// implementation, cpp file
int OtherType::classCounter = 0;
C++17开始,优化了这个细节,使用inline static member,直接在定义时初始化,无需在代码文件中做这个事情了,这样C++代码优雅了不少!示例代码如下:
// a header file, C++17:
struct OtherType {
inline static int classCounter = 0;
// ...
};
而const static member,也只能做in-class初始化:(也许应该使用constexpr,编译期也可以用)
#include <iostream>
using namespace std;
struct xyz {
int a;
int b;
const static int c {3};
int d;
xyz(int a, int b, int d): a{a},b{b},d{d} {}
};
//int xyz::c{3}; // not needed anymore!!
int main(void){
xyz x{1,2,4};
cout << x.a << x.b << xyz::c << x.d << endl;
return 0;
}
还需要注意static member的可访问范围,如果不是public,只有成员函数可以访问。
#include <iostream>
using namespace std;
class xyz {
protected:
static int a;
public:
static void set_a(int b);
void show_a(void);
};
int xyz::a = 1;
void xyz::set_a(int b) {
a = b; // a is the static one
}
void xyz::show_a(void) {
cout << a << endl;
}
int main(void) {
// cout << xyz::a << endl; // wrong, xyz::a is protected!!
xyz x;
x.show_a();
xyz::set_a(10); // right
x.show_a();
return 0;
}
C++ class中的static成员变量,类似python的class variable
上面的例子展示了一个static成员函数的case。
static成员函数同样不与对象绑定,对它的调用,虽然可以通过对象,但推荐使用class::static_function
的方式。静态成员函数仅能访问静态数据成员或其他静态成员函数,它们无法访问类的非静态数据成员或成员函数,因为他们没有this指针!
不同对象的这个拥有static变量的成员函数,共享这个static变量,在多线程场景下,如果不加保护,这种用法恐怕会有问题:
#include <iostream>
using namespace std;
struct bob{
int a;
bob(int a): a{a} {}
void show(void){
static int b = 11;
cout << a << " " << b++ << endl;
}
};
int main(void) {
bob b1{1};
b1.show(); // 1 11
bob b2{2};
b2.show(); // 2 12
bob b3{3};
b3.show(); // 3 13
return 0;
}
static class variable是所有对象的所有接口共享。static function variable是所有对象的那个具体的function共享。
如下测试代码:
$ cat test_static.cpp
#include <iostream>
using namespace std;
class xyz {
protected:
static int a;
public:
static void set_a(int b);
void show_a(void);
};
int xyz::a = 1; // must be defined outside class xyz
void xyz::set_a(int b) {
a = b; // a is the static one
}
void xyz::show_a(void) {
cout << a << endl;
}
class x2: public xyz {};
int main(void) {
// cout << xyz::a << endl; // wrong reference of xyz::a
x2 x;
x.show_a();
x2::set_a(10); // right
x.show_a();
xyz y;
y.show_a();
xyz::set_a(99);
x.show_a();
return 0;
}
输出:
$ g++ test_static.cpp
$ ./a.out
1
10
10
99
static成员变量,只有一个副本,继承后,不管是父类对象还是子类对象,指向相同。
?
本文链接:https://cs.pynote.net/sf/c/cpp/202207211/
-- EOF --
-- MORE --