1

C++ 中的 static

 2 years ago
source link: https://muyuuuu.github.io/2022/05/12/cpp-static/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C++ 中的 static

2022-05-12

16 2.2k 2 分钟

之前对 static 的理解仅限于:在类中声明这种类型的变量,可以通过这个变量知道这个类被创建了多少个对象。但是前些日子刷 leetcode 的时候,发现类中自定义的 cmp 函数如果不是 static 类型,就无法被类内的 sort 函数识别。所以今天来一探究竟。

其实 C 语言中也有 static 这个关键字,在全局区分配内存,或者说可以理解为全局变量,来回顾一下:

  1. 在全局区分配内存,自动初始化为 0,注:全局区就是静态区
  2. 在声明的整个文件是可见的
  3. 不会因子函数的退出而被释放空间,即子函数被执行完成初始化后,之后的调用不会再初始化,但作用域是局部的
  4. 修饰普通函数,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。

全局变量:

#include <iostream>

static int test;

void sub_func() {
test += 1;
}

int main() {
test += 1;
std::cout << test << std::endl; // 1
sub_func();
std::cout << test << std::endl; // 2
return 0;
}

局部变量:

#include <iostream>

void sub_func() {
static int test;
test += 1;
std::cout << test << std::endl;
}

int main() {
// 无法访问 test
sub_func(); // 1
sub_func(); // 2
return 0;
}

static 成员变量

  1. 这个类的所有对象都可以访问静态成员变量,一个对象修改,其他对象也会改变。说高级一些,不随对象创建而分配内存,不随对象销毁而释放内存
  2. 存储在全局区
  3. 必须类外初始化
  4. 可以通过类名访问
#include <iostream>

class A{
public:
static int num;
A(){
A::num += 1;
}
void increase(int a) {
// 类名访问
A::num += a;
}
};
// 类声明的外部初始化
int A::num = 0;

int main() {
A a;
A b;
std::cout << A::num << std::endl; // 2
b.increase(18);
std::cout << A::num << std::endl; // 20
return 0;
}
  1. 静态成员函数仅可以访问静态成员、函数;不能访问非静态成员、函数
  2. 非静态成员函数可以任意访问静态成员、函数
  3. 不需要 this 指针的额外操作
  4. 可以通过类名访问

来看一个 static 的成员函数,顺便解答本文开始的疑问。

#include <iostream>
#include <algorithm>
#include <vector>

class A{
public:
static int num;
int a = 10;
static auto get_num() {
// 错误,不能访问非 static 变量
// 毕竟全局区不能访问堆栈区
// return a + A::num;
return A::num;
}
// 如果不加 static
// 错误:对非静态成员函数‘bool A::cmp(int&, int&)’的使用无效
// 因为 sort 这个函数是全局的,找不到类内的 cmp
static bool cmp(int& a, int& b) {
return a > b;
}
void sort(std::vector<int>& arr) {
std::sort(arr.begin(), arr.end(), cmp);
}
};
// 类声明的外部初始化
int A::num = 0;

int main() {
A a;
A b;
std::vector<int> arr{3, 2, 4, 6, 2, 5, 7};
a.sort(arr);
for (auto i : arr) {
std::cout << i << " ";
}
return 0;
}

:: 扩展

上面写了很多 ::,江湖人称范围解析运算符,顺手总结一下:

  1. ::variable,全局作用域符,作用域是全局空间,如 ::isspace
  2. class::variable,某个类的作用域范围
  3. namespace::variable,某个命名空间的作用域范围。重点是,static 声明的链接性为内部静态变量的东西,可以使用未命名的 namespace 代替。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK