2011-08-11 25 views
3

我已经使用extern消除了翻译单元中的两个标题包含。这是可取的吗?建议使用extern来避免头依赖?

我的具体情况:我有一个名为ParseTree的课,累计Token*的。 ParseTree*Parser的私人成员。

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

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

分析我的代码后,我孤立,实际上有外部依赖的两种功能,并更换了包括以下各项:

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时,我应该注意哪些隐患?

+2

外部链接是函数声明的默认值,所以'extern'本身是多余的。 –

+0

这是我忽略的一个很好的观点。 –

回答

7

如果您使用extern声明,则无需重复自己,只需在任何地方重新使用该函数的原型即可。使用头文件,如果你想改变原型,你只需要在一个地方改变它。

所以不行,当你已经有合适的头文件时不要使用extern

+0

人们似乎强烈建议减少依赖关系,并尽量减少翻译单元之间的关系。例如,pimpl和前向声明。这种技术与这两种技术有什么不同? Pimpl成语尤其具有潜在的缺点/复杂性。 –

+0

对于“合适的头文件”+1。当许多大型头文件被单个包含链接时,我已经看到使用其他选项作为构建时优化。 –

+1

@Jordan:当你更新真正的(一个)定义时,你不必更换小馅饼。你所描述的*是*前向声明,理想情况下它将包含在一个“合适的”(而不是依赖性膨胀的)头文件中。 –

1

这两种解决方案似乎都起作用。在选择包含extern时,我应该注意哪些隐患?

是的。 API可能正在改变,编译器不会为你工作,它会对你不利。

学习如何使用编译器。不,从长远来看,不仅仅是“现在”,我的意思是。长期来说,你犯了愚蠢的错误,而不是当你头脑中有新鲜事物的时候。是的,你的大脑记忆是不稳定的。

1

通常通过前向声明类来减少依赖关系。这是一个例子。假设我们有两个前提头,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 
}; 

现在,有一个“用户,H”,它采用这两个,而不是喜欢写它:

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

void useParserAndToken(Parser &, Token &); 

你写

class Parser; 
class Token; 

void useParserAndToken(Parser &, Token &); 

这样你最终会说有类Parser和Token,但它们的定义完全无关紧要。这导致更快的编译。

为了减少依赖关系,您通常只会转发声明类。另一方面,复制函数声明没有多大意义。