C++ 建议使用extern来避免标头依赖性吗?

C++ 建议使用extern来避免标头依赖性吗?,c++,coding-style,include,extern,C++,Coding Style,Include,Extern,我使用extern消除了翻译单元中包含的两个标题。这样做明智吗 我的具体情况是:我有一个名为ParseTree的类,它积累Token*ParseTree*是解析器的私有成员 最初,我在parse_tree.cc中有以下几行代码 #include "parser.h" #include "token.h" 在分析代码之后,我隔离了两个实际具有外部依赖关系的函数,并用以下内容替换了include: extern std::ostream& operator<<(std::ost

我使用extern消除了翻译单元中包含的两个标题。这样做明智吗

我的具体情况是:我有一个名为
ParseTree
的类,它积累
Token*
ParseTree*
解析器的私有成员

最初,我在
parse_tree.cc
中有以下几行代码

#include "parser.h"
#include "token.h"
在分析代码之后,我隔离了两个实际具有外部依赖关系的函数,并用以下内容替换了include:

extern std::ostream& operator<<(std::ostream& out, const Token& t); // @token.h
extern bool hasPriority(const Token* p_tok1, Token* p_tok2); // @parser.h

extern std::ostream&operator如果您使用
extern
声明,那么无论您在何处使用函数原型,您都会不必要地重复自己。对于头文件,如果要更改原型,只需在一个位置进行更改

因此,如果已经有了合适的头文件,就不要使用
extern

这两种解决方案似乎都有效。在选择extern而不是include时,是否有任何我应该注意的隐患

对。API可能正在更改,编译器不会为您工作,它会对您不利


学习如何利用编译器为您带来好处。不,不仅仅是“现在”,从长远来看,我是说。从长远来看,你会犯愚蠢的错误,而不是当你脑子里什么都是新鲜的时候。是的,你的大脑的记忆在某种程度上是不稳定的。

通常通过向前声明类来减少依赖性。这里有一个例子。假设我们有两个先决条件头,parser.h和token.h,定义如下:

parser.h:

class Parser
{
public:
  void doFoo();
  void doBar();
  // ... lots of other stuff
};
token.h:

class Token
{
public:
  void doQuux();
  void doBaz();
  // ... continues for a while
};
现在,有一个“user,h”使用这两个,而不是像这样写:

#include "parser.h"
#include "token.h"

void useParserAndToken( Parser &, Token & );
你写

class Parser;
class Token;

void useParserAndToken( Parser &, Token & );
这样,您最终会说有类解析器和令牌,但它们的定义方式并不重要。这将导致更快的编译


为了减少依赖性,通常只向前声明类。另一方面,复制函数声明没有多大意义。

人们似乎强烈建议减少依赖性,并将翻译单元之间的关系保持在最低限度。例如,pimpl和转发声明。这项技术与这两项有什么不同?尤其是Pimpl习惯用法有很多潜在的缺点/复杂之处..+1表示“合适的头文件”。当许多大的头文件被一个include链接时,我看到了另一个选项作为构建时优化的用途。@Jordan:当您更新真(一)定义时,您不必更改pimpls。您所描述的是转发声明,理想情况下,它将包含在“适当”(而不是依赖项膨胀)头文件中。@Jordan:对于Pimpl,您不会更改Pimpl指针的类型。使用转发声明,您不太可能更改类型的名称。但是使用函数,您可以轻松地将参数的定义更改为该函数。这只是变化频率的问题。此外,人们通常建议在标题中提出声明,该标题与这些类型的定义不同。这样,如果您需要声明,您可以包含一个小标题。@Jordan,如果您认为值得,您可以创建新的标题,这些标题将包含在parse_tree.cc、parser.h和token.h中;但我强烈建议不要违反两条规则:头应该是自包含的(理想情况下,通过有第一个头的CU来强制执行),并且,除了类之外,最多应该有一个声明不是定义,需要它的CU应该包括包含它的文件。最小化包含的数量是值得的,但要服从这些规则。外部链接是函数声明的默认值,因此
extern
本身是多余的。这是我忽略的一个非常好的点。