基础介绍
关键字extern可以应用于全局变量,函数或模板声明。它指定符号具有external(外部的)链接
1. 在非const全局变量声明中,extern指定变量或函数在另一个转换单元中定义
如:在B的cpp文件中定义和声明一个全局变量g_i,然后在A的cpp中定义和声明同样一个全局变量g_i = 10,在编译时会存在重复定义的问题(是因为都存储在静态存储区嘛,会形成相同的符号表,导致符号表冲突?)
#include "B.h"
//B.cpp 中
int g_i = 10;
#include "A.h"
//A.cpp
int g_i = 10;
这种情况下,只需要将其中一个cpp中的全局变量前面加上extern关键字即可
#include "B.h"
extern int g_i;
2. 在const变量声明中,它指定变量具有external链接(默认情况下,全局const变量具有内部链接)
如在A.cpp中声明和定义一个g_i的const变量,B.cpp中也同样声明一个,此时没有编译问题,且可以正常打印
#include "A.h"
#include <iostream>
//A.CPP中
const int g_i = 100;
void A::print() {
std::cout<<g_i<<std::endl;//100
}
//B.CPP中
const int g_i = 10;
void B::print() {
std::cout<<g_i<<std::endl;//10
}
将A中的g_i前面加上extern关键字同时不进行定义,B.cpp中的g_i前面加上extern关键字,这样就可以正常在A.cpp中找到B.cpp中的变量
//A.cpp
extern const int g_i;
void A::print() {
std::cout<<g_i<<std::endl;/10
}
//B.cpp
extern const int g_i = 10;
void B::print() {
std::cout<<g_i<<std::endl;//10
}
3. extern “C” 指定使用c链接的方法
使用extern的特性实现开关模块
一般我们在上一些功能模块的时候,需要以下几个东西:
-
开关的key,一般是string类型
-
开关的默认值
-
开关的维护人
-
开关的描述
首先创建一个维护所有config 的文件:ABConfig.h
进行没有意义的define的
#if !defined(ABConfig)
#define ABConfig(...)
#endif
ABConfig(KEY_A,"a",false,"xiaoming","是一个bool 开关");
然后创建一个主要消费config 的模块,ABCenter.h,利用h文件会全部展开的特性,对ABConfig.h中的define进行字符串声明,使用extern方式
#include <string>
//利用.h的特征,对ABConfig重定义,进行声明
#undef ABConfig
#define ABConfig(keyID,key,...) extern const std::string keyID;
#include "ABConfig.h"
class ABCenter {
public:
static std::string getkey();
};
然后在ABCenter.cpp中,定义我们需要的key
#include "ABCenter.h"
#undef ABConfig
#define ABConfig(keyID,key,...) extern const std::string keyID = key;
#include "ABConfig.h"
std::string ABCenter::getkey() {
return KEY_A;
}
这样,其他h或者cpp文件中,需要使用ab的key时,就只需要#include "ABCenter.h",就可以获得相关的string了
#include <iostream>
#include "ABCenter.h"
int main() {
std::cout<<KEY_A<<std::endl;
return 0;
}