我在sample.h中声明了以下命名空间
// namespace with identifier
namespace N1
{
int b = 80;
}
sample1.cpp使用上面的命名空间声明
#include <iostream>
#include "sample.h"
using namespace std;
using namespace N1;
int main(void)
{
cout << "b (in main) = " << b << endl;
foo(); //written in sample2.cpp
return 0;
}
sample2.cpp也使用sample.h中声明的命名空间
#include <iostream>
#include "sample.h"
using namespace std;
using namespace N1;
void foo(void)
{
cout << "b = " << b << endl;
}
当我编译时,我得到了以下错误
$> g++ sample1.cpp sample2.cpp
/tmp/ccB25lEF.o:(.data+0x0): multiple definition of `N1::b'
/tmp/cchLecEj.o:(.data+0x0): first defined here
让我知道如何解决以及如何实施“ namespace std ”以避免此问题?
答案 0 :(得分:8)
这不是#ifndef
后卫的问题。
在头文件中使用extern
:
//sample.h
namespace N1
{
extern int b; //extern is MUST!
//DONT WRITE : extern int b = 80;
}
然后在.cpp文件中将其定义为:
//sample.cpp
namespace N1
{
int b = 80; //initialization should be here
}
答案 1 :(得分:5)
包含防护仅在编译期间有效,但错误发生在链接时。这是因为sample.h包含在两个编译单元中,并且两者都创建了变量N1::b
如果你真的想要一个变量(不是const
),你必须在标题中将它声明为extern
,并在一个单独的编译单元中为它创建一个内存位置:
// sample.h
#ifndef N1
#define N1
namespace N1 {
extern int b;
}
#endif
// sample.cpp
#include "sample.h"
namespace N1 {
int b = 80;
}
答案 2 :(得分:3)
是不是只是在sample.h文件中缺少一次ifdef或pragma?
答案 3 :(得分:3)
每次#include sample.h到.cpp模块时,它都会为b创建一个新的链接器记录,为你提供链接上的多个定义[1]。
int应该在sample.cpp中定义,或者在其他地方定义,并且在sample.h中只是extern int。
[1]一些链接器将忽略这一点,你将能够链接OK,但大多数情况下它会产生错误。
答案 4 :(得分:2)
您的问题是您在头文件中定义了具有外部链接的对象,该头文件包含在两个单独的编译单元中。该问题与命名空间无关。
一种解决方案是使头文件仅包含声明(例如,见下文)并将定义放在单个源文件中。
// sample.h
namespace N1
{
extern int b;
}
// sample.cc
namespace N1
{
int b = 80;
}
另一个解决方案是给对象内部链接,虽然这意味着你有多个名为b
的对象,但这可能不是问题。例如,如果b
应该是常量,那么这将起作用,因为const
对象默认具有内部链接。
// sample.h
namespace N1
{
const int b = 80;
}
答案 5 :(得分:1)
如果你想要的只是定义一个常量,那么试试这个:
namespace N1
{
enum MyEnum
{
b = 80
};
}
对于几乎任何.h文件,包含警卫都是一个好主意,但它们可能不是你的问题。最重要的One Definition Rule有两个主要部分:第一个表示每个符号每个翻译单元只能定义一次(通常表示.cpp文件)。这就是包含警卫的内容:它们防止标题被包含两次,这将导致在同一个翻译单元(= .cpp文件)中多次定义符号(如N :: b)。
但是,这不是全部。某些符号(如类,非内联函数和某些变量定义)只能为整个程序声明一次。这不是不合理的:让我们假设您允许在一个转换单元中将名为MyInt的int值定义为40,在另一个转换单元中定义为80:编译器如何知道要使用哪一个?当然,您可以每个程序多次声明这样的符号(但每个翻译单元只能一次) - 或者它们只能在声明它们的翻译单元中使用。但是你不能在多个翻译单元中定义。使用枚举是一种简单的方法,可以避免在你的情况下分离声明和定义(因为枚举不受一个定义规则的第二个版本的限制),但如果你真的需要一个(非常量)全局在int
类型中,您可以通过这种方式实现:
<强> sample.h 强>
namespace N1
{
// The extern keyword tells the compiler that this is is only
// a declaration and the variable is defined elsewhere.
extern int b;
}
<强> sample1.cpp 强>
#include "sample.h"
namespace N1
{
// This is the definition!
int b = 5;
}
void foo()
{
using namespace std;
cout<<N1:b<<endl;
}
<强> sample2.cpp 强>
#include "sample.h"
// No need to define N1::b, since it was already defined in sample1.cpp.
void bar()
{
using namespace std;
cout<<N1:b<<endl;
}
答案 6 :(得分:0)
该程序包含变量N1::b
的两个定义,而必须只有一个。该变量必须在extern
的标头中声明,并且只在一个源文件中定义。