07 | C++中的static和inline
非类的成员函数以及成员变量
-
inline修饰的函数或变量(c++17开始可以修饰变量)在全局保留一份;
-
static修饰的函数或者变量会在各自的编译单元都保留一份;
-
static函数的局部static变量也会有多份,inline函数的static变量只有一份;
-
static inline 修饰的函数或者变量与static单独修饰的效果一致;
-
inline 不能修饰局部变量;
有关类的成员函数以及成员变量
-
类的非const静态成员变量初始化,C++ 17可以通过static inline 在类内直接初始化,C++17之前必须在类外初始化(const static 修饰的变量也可以类内初始化,这个在之前也是可以的);
-
C++17之后,类的静态成员变量在类内通过static声明,在类外(但是在头文件中)初始化不加inline的话可能会导致重定义从而出现链接错误,而加了inline 就不会出错,类似有无inline修饰的全局函数;
-
C++ 17之前必须在.cpp中初始化静态成员才不会出现重定义的错误,在.h中初始化还是会导致重定义错误,因为C++17之前的标准不支持inline修饰类的静态成员变量;
-
类中的函数其实可以认为是都隐式加了inline的,因为类中的所有函数在全局都只有一份,而有无static修饰只是限制该函数对类数据成员的使用(类的static函数只能使用static成员变量,类的普通成员函数可以使用所有的成员变量 );
C++ 17之前为什么类的非const静态成员必须类外初始化?
- 因为类的静态成员是类所有,不属于任何对象,如果放在类内初始化,那么每个对象构造的时候都会对该静态成员进行初始化,这样会导致其他对象在使用该静态成员时出现意想不到的错误,所以禁止类内初始化非const静态变量;
- 而const修饰的静态成员变量是在类中初始化,对象构造的时候不会再进行初始化操作,对象构造的时候默认该变量已经初始化了,反正也不能修改它;
- C++17之前的类内静态变量必须在类外初始化,如果有头文件和实现文件,最好在类的实现文件中对静态变量做初始化,如果在头文件中做初始化,也会引起重定义的问题;
- C++17 之后可以在类内通过static inline 直接进行声明与初始化,也可以在类内部进行声明,在类外(但是在头文件中)通过inline 进行初始化。其实就是新标准通过inline能够保证类内静态变量只初始化一次,全局共享一份数据,而之前的标准是不允许inline修饰类的静态成员变量的;
举个现实中的小例子
第一阶段
main.cpp
#include "test.h"
#include "test2.h"
int main() {
}
test.h
bool a = true;
test2.h
#include "test.h"
我们看一下编译结果
是编译期出现的问题
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2374 “a”: 重定义;多次初始化
第二阶段
我们将 test.h修改如下
#pragma once
bool a = true;
我们接着编译一下
是链接期出现的问题
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2005 "bool a" (?a@@3_NA) 已经在 test.obj 中定义
第三阶段
我们将 test.h修改如下
#pragma once
inline bool a = true;
生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个
相信大家看到这里就明白 inline 变量的一个使用场景了!
当然你也可以将其定义放到.cpp文件中,同样可以避免第二阶段链接期的错误!