2012-12-31 163 views
0

内general.h中如何避免链接错误

#ifndef GENERAL 
#define GENERAL 
namespace counternamespace{ 
    int upperbound; 
    int lowerbound; 
} 
#endif 

内Analyzer.h

#ifndef ANALYZER 
#define ANALYZER 
#include"General.h" 

class Analyzer 
{ 
public : 
    int var ; 
    int func(); 
}; 
#endif 

内Test.h

#ifndef TEST 
#define TEST 
#include"Analyzer.h" //Error 
class Test2 
{ 
public: 
    Test2(void); 

public: 
    ~Test2(void); 
}; 
#endif 

在上面的代码时,我不在Test.h里面加分析器一切正常。但添加后显示以下链接器错误。

1>Test2.obj : error LNK2005: "int counternamespace::lowerbound" ([email protected]@@3HA) already defined in Analyzer.obj 
2>Test2.obj : error LNK2005: "int counternamespace::upperbound" ([email protected]@@3HA) already defined in Analyzer.obj 

我已经加入了#ifndef/#endif。那么我在哪里做错了?任何人都可以让我知道吗?

回答

1
Inside General.h 

#ifndef GENERAL 
#define GENERAL 
namespace counternamespace{ 
    extern int upperbound; 
    extern int lowerbound; 
} 
#endif 

Inside General.cpp 

#include"General.h" 
using namespace counternamespace ; 
int counternamepace::upperbound = 12; 
int counternamepace::lowerbound = 12; 

然后做任何需要的。

1

你不应该在头文件中定义任何变量。
在每个翻译单元中创建变量的副本当您将头文件包含在其他文件中时,因此违反了一个定义规则并导致链接错误。

+0

:好的。留下Test2.h文件。 Analyzer.h内部也包含了一般的.h文件。因此,在这种情况下,由于分析器和通用转换单元中的名称空间定义,应该存在一些链接器错误。但它没有显示任何链接器错误。你能澄清一下吗? – Kenta

+0

@Learner你有Analyser.cpp和Test2.cpp,两者都是不同的编译单元。 –

+1

我已在此解决方案中添加了详细信息,并在我的答案中添加了解决方案。 –

2

是的,Alok有权利。你大概有Analyser.cpp和Test2.cpp,都是不同的编译单元。当你打电话

g++ Analyser.cpp Test2.cpp 

编译器实际上使Analyser.obj和Test2.obj分开并将它们链接在一起。 当编译器试图将Analyser.obj和Test2.obj链接在一起时,它意识到Test2.obj中的两个变量也存在于Analyser.obj中。

#define指令不工作,因为它们只存在于一个单一的编译单元,所以general.h中包含在Analyser.obj和Test2.obj都

为了避免这种重复,the solution is wrapping your namespace variables围绕着一个函数。它是这样的:

内general.h中

#ifndef GENERAL 
#define GENERAL 
namespace counternamespace{ 
    int& upperbound(); 
    int& lowerbound(); 
} 
#endif 

内General.cpp

#include "General.h" 
namespace counternamespace{ 
    int& upperbound(){static int local; return local;} 
    int& lowerbound(){static int local; return local;} 
} 

因此可以这样说,现在

counternamespace::upperbound()=3; 
counternamespace::lowerbound()=1; 

,这意味着和你一样本来会说

counternamespace::upperbound = 3; 
counternamespace::lowerbound = 1; 

不用担心,编译器会优化掉函数调用,所以也没有开销。

+0

谢谢现在错误消失了。但是我如何访问Analyzer内的counternamespace,我现在无法访问counternamespace。 – Kenta

+1

@Learner:你可以像以前一样访问'counternamespace'。 “upperbound”和“lowerbound”之后的附加括号除外,没有任何变化。 –