C ++ Namespace成员访问不同的文件如何? “namespace std”如何实现?

时间:2011-05-24 10:45:14

标签: c++ namespaces

我在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 ”以避免此问题?

7 个答案:

答案 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的标头中声明,并且只在一个源文件中定义。

相关问题