基本概念
- 编译单元
由.cpp(.c)文件及include的.h文件构成一个编译单元(把头文件内容复制到cpp中),在编译时,编译为一个.obj文件,obj文件里包含了变量存储的相对地址。 - 声明与定义
函数或变量在声明时,并没有分配实际物理内存空间;当函数或变量定义时会分配物理内存空间,并有相应的地址。
extern、static、const
- extern
extern 有两个作用:
当extern与“c”在一起使用时,如:extern “C” void fun(int a,int b)则告诉编译器fun这个函数名时按着c的规则去翻译相应的函数名而不是c++的,c++的规则在翻译这个函数名时,会把fun更改为?fun@CDataView@@QAEXHH@Z类似这样的名字。在生成dll提供给外部调用时尤其要注意,例如C#通过Import调用非托管代码时需要匹配函数名。
c++规则编译的函数名:
extern c规则编译的函数名:
当extern 不与“c”一起修饰变量或函数时,其作用就是声明函数或变量的作用范围。extern的作用范围为本模块或其他模块。extern是一个声明不是定义。
//test.h
//声明全局变量,一个程序中可以不声明或任意次声明,声明是为了告诉当前编译单元去寻找此全局变量
extern char[] g_username;
//test.cpp
//定义全局变量
#include "test.h"
char[] g_username="admin";
声明可以有多个,定义只能有一个!
我们可以在所有的文件中不#include “test.h”而是都写上extern char[] g_username,一样可以正常使用。
- static
static 和 extern “水火不容”,static和extern不能同时修饰一个变量!
static 修饰的全局变量声明与定义同时进行,声明后就同时被定义了。
static 修饰的全局变量的作用域只是本身的编译单元(.cpp)内,其他编译单元看不到它,所以一般定义static全局变量时都是放在cpp中而不是头文件,这样不会给其他模块造成不必要的污染。
对于第三点,static的作用域可能大家不理解,一下用代码来验证一下:
//test1.h
//分别用数值和指针进行验证
#include <iostream>
using namespace std;
static int flg=2;
static char name[]="admin";
void fun1();
//test1.cpp
#include "test1.h"
void fun1()
{
flg=5;
cout<<"test1 flg value:"<<flg<<endl;
name[0]='c';
cout<<"test1 name value:"<<name<<endl;
}
//test2.cpp
#include "test1.cpp"
void fun2()
{
cout<<"test2 flg value:"<<flg<<endl;
cout<<"test2 name value:"<<name<<endl;
}
void main()
{
fun1();
fun2();
}
结果:
它们之所以可以连接成功而没有报重复定义的错误是因为虽然它们有相同的内容,但是存储的物理地址并不一样,就像是两个不同变量赋了相同的值一样,而这两个变量分别作用于它们各自的编译单元。
正是因为static有以上的特性,所以一般定义static全局变量时,都把它放在原文件中而不是头文件,这样就不会给其他模块造成不必要的信息污染,同样记住这个原则!
类中静态成员初始化问题
参考static成员必须在类外初始化
在一次使用单例模式时,类中需要有一个当前类的静态对象,且有默认空的值,若像局部静态变量声明同时定义则会报错
为什么不能在类内初始化???下次再仔细分析
先看如何在类外初始化,上代码:
//单例
class CConfigSetting
{
private:
CConfigSetting();
~CConfigSetting();
//类内声明
static CConfigSetting* m_cfgSetting;
public:
sDbCfg dbSetting; //数据库连接设置
int port; //端口号
sTimerCfg timerSetting; //定时器设置
static CConfigSetting CreateInstance();
void Save();
};
//类外初始化
CConfigSetting* CConfigSetting::m_cfgSetting = nullptr;
3. const
const 是常量
在头文件(被多次include)中定义const char g_str[]=”admin”不会报错,但是const char * g_str=”admin”会报错。
const char g_str[]=”admin”与static const char * g_str=”admin”、const char* const g_srt=”admin”效果一样,都不可被修改。
const char * g_str=”admin” 可被修改:g_str=”ccc”;