C++命名空间成员在不同文件中的访问如何?"namespace std"如何实施?
C++ Namespace member access in different files how to? how "namespace std" implemented?
我已经在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
让我知道如何解决以及如何实现"命名空间std"以避免此问题?
这不是#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
}
Include guards仅在编译时工作,但错误发生在链接时。这是因为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;
}
这不是示例.h文件中缺少一次ifdef或pragma吗?
每次将sample.h#包含到.cpp模块中时,它都会为b创建一个新的链接器记录,从而在链接[1]上为您提供多个定义。
int应该在sample.cpp中定义,或者在其他地方定义,并在sample.h中简单地外部int b。
[1] 有些链接器会忽略这一点,你可以正常链接,但大多数时候它会产生错误。
您的问题是在头文件中定义了一个具有外部链接的对象,该头文件包含在两个独立的编译单元中。这个问题与名称空间本身无关。
一种解决方案是使头文件仅包含声明(例如,见下文),并将定义放在单个源文件上。
// 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;
}
如果您只想定义一个常量,请尝试以下操作:
namespace N1
{
enum MyEnum
{
b = 80
};
}
对于几乎任何.h文件,包含保护程序都是个好主意,但它们可能不是你的问题。至关重要的一个定义规则有两个主要部分:第一部分说每个符号在每个翻译单元只能定义一次(通常意味着.cpp文件)。这就是include保护的作用:它们防止标头被包含两次,这将导致符号(如N::b)在同一转换单元(=.cpp文件)中被定义多次。
然而,这还不是全部。某些符号,如类、非内联函数和某些变量定义,对于整个程序只能声明一次。这并非没有道理:假设您允许在一个翻译单元中将一个名为MyInt的int值定义为40,在另一个转换单元中将其定义为80:编译器如何知道该使用哪一个?当然,您可以为每个程序多次声明此类符号(但每个翻译单元只能声明一次),或者它们只能在声明的翻译单元中使用。但您不能在多个翻译单元中定义它们。
使用enum是避免在您的情况下必须分离声明和定义的一种简单方法(因为enum不受第二版本的One definition规则的约束),但如果您真的需要int
类型的(非常量)全局,则可以通过以下方式实现:
样本.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;
}
程序包含变量N1::b
的两个定义,而必须只有一个。变量必须在标头中用extern
声明,并且只能在一个源文件中定义。
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 实施具有 C++20 概念的配对概念
- Python中的for循环与C++有何不同
- "using namespace std;"在C++的作用是什么?
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 在C++中释放内存期间,迭代器与指针有何不同
- 如何在C++中最好地实施"newtype"成语?
- 如何在MISRA C++之后实施CRTP
- 为什么我需要做'using namespace std'而不是"使用 std::cout"?
- 'using namespace'实现细节的便捷方法(仅标头库)?
- 所以我正在为我的学校作业练习继承,但我无法正确实施标题保护
- C++强制实施方法?
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- C++中"typedef"、"using"、"namespace"和"using namespace"有什么区别?
- shift_right() 打算如何在 C++20 中实施?
- 如何减少对 std::type_index 的实施?
- DFS 在 C++ 中的实施
- 实施英特尔实感和 SDL2 时出现问题
- 为什么海湾合作委员会在实施is_nothrow_constructible时需要static_cast?
- C++命名空间成员在不同文件中的访问如何?"namespace std"如何实施?