header_only 头文件实现的关键点
-------------------------------------------------------------------------
 author: hjjdebug
 date:   2023年 11月 28日 星期二 16:58:38 CST
 descriptor: header_only 头文件实现的关键点
1. 对外声明的函数必需加上inline, 消除连接的歧义
2. 在inline 函数内部声明的static 对象, 在多个文件包含时,对象是唯一的
 -------------------------------------------------------------------------
看到一个loger 文件,它只有头文件,变量,代码的实现都在一个头文件中, 那它是如何解决下面2个问题的.
问题1: 在多个文件中包含一个header_only 头文件, 里面如果有定义变量, 它肯定应该是一个, 那它是怎么做到的?
 问题2:在多个文件中包含一个header_only 头文件, 把函数体写在.h 文件中,怎样避免函数重复定义?
 我这里写了一个简单的测试用例,搞清楚了这两个问题。代码copy 下来编译是可以通过的.
$cat header_only.h 
 #ifndef _HEAD_ONLY_H
 #define _HEAD_ONLY_H
 #include <stdio.h>
 class _MY_OBJ
 {
 public:
     _MY_OBJ(){_hide = 0;}
     void setData(int d){_hide = d;}
     void print_it(){printf("data is %d\n",_hide);}
 private:
     int _hide;
 };
 //一般做法行不通,有2个问题
 //static _MY_OBJ s_obj;  在全局变量位置声明的static 变量, 每包含一次会生成一个全局的对象, 必需修改!
 //_MY_OBJ *getDefaultObj(){return &s_obj;} //有multiple definition of `getDefaultObj()' 连接有问题,必需修改!
 //                      
 //1. 必需加上inline, 消除连接问题 多重函数定义
 inline _MY_OBJ *getDefaultObj()
 {
     static _MY_OBJ s_obj;  //2. 在inline 函数内部声明的static 对象, 在多个文件包含时,对象是唯一的
     return &s_obj;
 }
 //所以header_only 头文件的关键是2点
//1. 必需加上inline, 消除连接问题 多重函数定义
//2. 在inline 函数内部声明的static 对象, 在多个文件包含时,对象是唯一的
 #endif
我们在main.cpp 和 other_file.cpp 中都包含这个header_only.h, 都来调用obj->print_it(), 发现这是同一个obj
 代码如下:
$cat main.cpp 
 #include "header_only.h"
 #include "other_file.h"
 int main()
 {
     _MY_OBJ *obj = getDefaultObj();  // main 函数中得到一个obj
     obj->setData(3);
     obj->print_it();
     other_print(); // other_file 中也会得到一个obj, 但它们是同一个obj
     return 0;
 }
$cat other_file.h
 #ifndef _OTHER_FILE_H
 #define _OTHER_FILE_H
 void other_print();
 #endif
$ cat other_file.cpp
 #include "other_file.h"
 #include "header_only.h"
void other_print()
 {
     _MY_OBJ *obj=getDefaultObj();
     printf("in other file print.\n");
     obj->print_it();
 }
该函数的执行结果:
$ ./head_only 
 data is 3
 in other file print.
 data is 3
从运行结果上可以看出, main中得到的obj与other_file中得到的obj是同一个obj
  
小结:
 是的,问题是解决了,问题到底是谁解决的? 你可以说是自己,但其实真正的问题解决者是gcc.
 当你在头文件中声明inline 函数时, gcc 就会试图在本地展开函数代码, 如果它不方便展开,也会分解为多次调用,一次实现的方式. 以便满足函数不重复定义的要求.
 这不就是我们费半天一天不见得把复杂的header_only文件拆分成.h和.cpp文件的工作吗
 而gcc 瞬间就帮我们搞定了. 你在inline 函数内声明的static 变量,由于其只有一处实现,所以就是唯一的了.
 所以说,牛X的是gcc ,我们只是牵了一下牛鼻子而已!