【C++】static(静态)

类外

静态变量或函数意味着,当需要将这些变量或函数与实际定义的符号链接时,链接器不会在这个翻译单元的作用域之外寻找那个符号定义,即只会在这个翻译单元内部链接(文件内可用)

如果这句话并不理解,可以看一下【C++】How the C++ Compiler Works【C++】How the C++ Linker Works

示例:

Main.cpp

c++ 复制代码
#include<iostream>
int s_Variable = 10;
int main() {
	std::cout << s_Variable << std::endl;
}

Static.cpp

c++ 复制代码
static int s_Variable = 5;

没有问题,输出10

当删掉static int s_Variable = 5;中的static后,报错了

我们可以将int s_Variable = 10;改为extern int s_Variable;

没有问题,输出5

函数也是类似的,动手试一试吧

类内

静态成员:指的是在C++类中声明成员时,可以加上static关键字,这样声明的成员叫静态成员。静态成员分为静态数据成员和静态函数成员两种。

静态数据成员定义

c++ 复制代码
class node{
    public:
    	static int id;//静态数据成员定义
}
int node::id=10;//静态数据成员类外初始化

静态数据成员的特点

  1. 类中的静态数据成员,所有对象都共享该数据,只有一份内存在内存中
  2. 类中的静态数据成员,必须要在类外初始化,因为它不属于对象,而是属于类。对象不管是否存在,这个静态数据成员都是存在的,而且静态数据成员的生命周期是程序开始就存在(主函数运行之前),直到程序结束才会被释放
  3. 类中的静态数据成员,可以在类中被重新赋值,可以被普通函数访问,如果该成员是公有属性,那么还可以在类外被对象自己访问(没什么意义),或者通过类名访问

静态函数成员定义

c++ 复制代码
class node{
    public:
    	static void fun(){}//在类中定义
    	static void fun1();//在类中声明
}
void node::fun1(){}//在类外定义

静态函数成员的特点

  1. 类中的静态函数成员,这个函数同样也不属于对象,而是属于类的,所以在这个函数中不能操作类中的普通数据成员和普通成员函数。因为这些普通成员是必须要有对象的时候才会被建立,而静态函数不用对象也能调用
  2. 访问和静态数据成员一致
  3. 可以在这个静态函数中使用局部变量、形参、静态数据成员

示例:

c++ 复制代码
#include<iostream>
struct Entity {
	int x, y;
	void print() {
		std::cout << x << "," << y << std::endl;
	}
};

int main() {
	Entity e;
	e.x = 2;
	e.y = 3;
	Entity e1;
	e1.x = 5;
	e1.y = 8;
	e.print();//2,3
	e1.print();//5,8
}

将x和y变为静态的:static int x, y;

并在结构体下面定义静态变量:

c++ 复制代码
int Entity::x;
int Entity::y;

输出:

5,8
5,8

e1.x = 5;像这样引用没什么意义

可以像这样引用:Entity::x = 5;

同样地,将print函数改为静态的

e.print();可以写成Entity::print();

也就是说我们没有必要实例化对象就能使用静态变量和方法

那么,上面的代码可以改为

c++ 复制代码
#include<iostream>
struct Entity {
	static int x, y;
	static void print() {
		std::cout << x << "," << y << std::endl;
	}
};
int Entity::x;
int Entity::y;
int main() {
	Entity::x = 6;
	Entity::y = 7;
	Entity::print();
}

上面我们说它们属于类,是指它们是类中的一部分,实质上它们和在命名空间中一样

如果我们让方法保持静态,变量不为静态,改成下面这样:

c++ 复制代码
#include<iostream>
struct Entity {
	int x, y;
	static void print() {
		std::cout << x << "," << y << std::endl;
	}
};

int main() {
	Entity e;
	e.x = 6;
	e.y = 7;
	Entity::print();
}

出现报错:对非静态成员"Entity::x"的非法引用

你不能从静态方法访问它,因为静态方法没有类实例

局部静态(Local Static)

静态局部变量允许我们声明一个变量,它的生命周期基本上相当于整个程序的生命周期,但是它的作用域范围是被限制的。你可以在任何作用域中声明,如果在函数中声明,那么它的作用域范围被限制在这个函数中。

示例:

c++ 复制代码
#include<iostream>
void Function() {
	static int i = 0;
}

int main() {
	Function();
}

输出:

1
2
3
4
5

这意味着当我第一次调用函数时,这个变量将被初始化为0,然后所有对函数的后续调用实际上不会创建一个全新的变量

而下面这种情况就不会这样

c++ 复制代码
#include<iostream>
void Function() {
	int i = 0;
	i++;
	std::cout << i << std::endl;
}

int main() {
	Function();
	Function();
	Function();
	Function();
	Function();
}

输出:

1
1
1
1
1

改变作用域范围也会达到同样的效果

c++ 复制代码
#include<iostream>
int i = 0;
void Function() {
	i++;
	std::cout << i << std::endl;
}

int main() {
	Function();
	Function();
	Function();
	Function();
	Function();
}

输出:

1
2
3
4
5

但这种方法的问题是我可以在任意地方访问i

	Function();
	i=10;
	Function();
	Function();
	Function();
	Function();

输出:

1
11
12
13
14

示例------单例类

c++ 复制代码
#include<iostream>
class Singleton {
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get() {
		return *s_Instance;
	}
	void Hello() {
	}
};
Singleton* Singleton::s_Instance = nullptr;
int main() {
	Singleton::Get().Hello();
}

我们可以简化它

c++ 复制代码
#include<iostream>
class Singleton {
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get() {
		static Singleton instance;
		return instance;
	}
	void Hello() {
	}
};
int main() {
	Singleton::Get().Hello();
}

这里就是作为例子,可以进一步了解:【C++】单例模式


static的五种用法

  1. 全局变量前加static修饰为文件作用域全局变量,内存在全局数据区
  2. 块作用域前加static修饰为块作用域变量,但内存在全局数据区
  3. 普通函数前加static修饰为文件作用域函数
  4. 类中数据成员前加static修饰为类中所有对象共享数据
  5. 类中函数成员前加static修饰为类中所有对象共享成员
相关推荐
小吉在努力敲代码中12 分钟前
c++实现B树(下)
开发语言·数据结构·c++·b树·算法
一只小松许️20 分钟前
现代C++HTTP框架cinatra
开发语言·c++·http
不爱学英文的码字机器27 分钟前
[C++] 智能指针
开发语言·c++·算法
♡喜欢做梦28 分钟前
【数据结构】栈和队列详解!!!--Java
java·开发语言·数据结构·链表
学习前端的小z29 分钟前
C语言和C++的常量概念与区别分析
c语言·c++
静止了所有花开31 分钟前
SpringSSM整合
java·开发语言·mybatis
Dreams°12333 分钟前
【JavaScript 网页设计实例教程:电商+视频】详细教程
开发语言·前端·javascript
小狮子安度因1 小时前
Qt文件目录操作
开发语言·qt
好开心331 小时前
javaScript交互补充3(JSON数据)
开发语言·前端·javascript·ecmascript·交互
0x派大星1 小时前
【Goland】——Gin 框架中间件详解:从基础到实战
开发语言·后端·中间件·golang·go·gin