我有一个声明两个全局对象的标头myglobal.h
:
#include "log.h" // defines Clog
Clog log_file;
#include "lib.h"
Clib main_lib;
但是,我的lib.h
也使用全局标头:
#include "myglobal.h" // error: circular #include
class Clib
{
void func(void) { log_file << "hello"; }
}
如何编写这些标头以避免#include
循环?
在头文件中添加extern
,
// myglobal.h
#include "log.h"
extern Clog log_file;
// #include "lib.h" DO NOT include this one
extern Clib main_lib;
然后在 cpp 文件 (log.cpp) 中定义它
#include "log.h"
Clog log_file;
并将 clib 的定义也move
到 cpp 文件(例如 lib.cpp)。
#include "myglobal.h"
void Clib::func(void) { log_file << "hello"; }
如果无法将定义移出头文件,则只需要一个 cpp 文件来定义Clib main_lib
。除此之外,只要您包含对所有标头的防护,它应该没问题。
循环 #include 的根本问题是循环思维。特别是,全局标头的概念既定义又依赖于您的库。
您可以通过不依赖于库实现中的myglobal.h
来解决此问题。一种简单的方法是将CLib::func
移动到lib.cpp
首先,如 CS Pei 的回答中所述,请注意您需要包含守卫,并且头文件中的变量声明需要extern
(以及源文件中的单独定义)。 在 C++17 中,您可以改用inline
,并让链接器对其进行排序。
同时,根据您的用例,有一些策略可供选择。
前向声明Clib
myglobal.h
只声明Clib
,而不是定义它:
#include "log.h"
extern Clog log_file;
class Clib;
extern Clib main_lib;
然后可以毫无问题地#include
lib.h
。 但是,单独#include"myglobal.h"
的客户端将无法使用main_lib
,因为它的类型不完整。
将log_file
放在其自己的标头中
由于Clib
不仅依赖于Clog
,还依赖于log_file
,因此它显然处于更高的接口级别。 通过创建globallog.h
将其形式化:
#include "log.h"
extern Clog log_file;
然后lib.h
可以包括没有循环性的内容:
#include "globallog.h"
class Clib
{
void func(void) { log_file << "hello"; }
}
最后,myglobal.h
包括这一点并添加main_lib
:
#include "globallog.h" // optional: clarifies that log_file is made available
#include "lib.h"
extern Clib main_lib;
声明全局对象及其类
在lib.h
中声明main_lib
如果没有文件想要没有(您当前的)myglobal.h
lib.h
(可能是因为唯一使用的Clib
是main_lib
),您可以将main_lib
声明移动到lib.h
:
#include "myglobal.h" // only log_file now
class Clib
{
void func(void) { log_file << "hello"; }
}
extern Clib main_lib;
请注意,这是之前"log_file
在其自己的标头中"策略的变体,其中log_file
是现有标头中唯一保留的内容。
在log.h
中声明log_file
对称地,如果没有文件想要log.h
而不使用log_file
,请在此处声明它并只留下myglobal.h
main_lib
:
#include "lib.h"
extern Clib main_lib;
那么lib.h
只是
#include "log.h"
class Clib
{
void func(void) { log_file << "hello"; }
}