您将需要三个不同的文件:header.h
,source.cpp
和main.cpp
。
// header.h
#pragma once
namespace A
{
namespace B
{
class C
{
public: static void f();
};
void g();
}
using namespace B;
}
// source.cpp
#include "Header.h"
namespace A
{
void C::f()
{
#pragma message( "Compiling " __FUNCTION__ )
}
void g()
{
#pragma message( "Compiling " __FUNCTION__ )
}
}
// main.cpp
#include "Header.h"
int main()
{
A::C::f();
A::g();
}
我预计没有错误,相反,看起来类和函数属于不同的命名空间,尽管在同一范围内声明和实现:
1 > Source.cpp
1 > Compiling A::B::C::f
1 > Compiling A::g
1 > Generating Code...
1 > ConsoleApplication10.obj : error LNK2019 : unresolved external symbol "void __cdecl A::B::g(void)" ( ? g@B@A@@YAXXZ) referenced in function _main
代码由工具生成。
谢谢
当你这样做时:
void C::f()
{
#pragma message( "Compiling " __FUNCTION__ )
}
此处f
是一个限定名称(由C
限定(。因此,C++必须弄清楚你在说什么C
。为此,它必须查看可用的非限定名称,并找到其中C
标识符。因为您处于命名空间A
中,并且命名空间A
已将所有命名空间B
转储到其中,所以C
将解析为A::B::C
。因此,C::f
变得A::B::C::f
.
相比之下,当您执行此操作时:
void g()
{
#pragma message( "Compiling " __FUNCTION__ )
}
g
是一个不限定的名称。因此,该名称的含义与它所说的完全一样:名称g
在当前命名空间中。这是A
.
using
声明不会更改当前命名空间;它只会更改名称的名称查找规则。因为g
是一个不合格的名字,所以没有什么可查的;你的意思是A::g
.
这意味着您没有定义函数A::B::g
。
所以你有一个标题,上面写着"我保证某人,某个地方会定义A::B::g
",但实际上没有人这样做。source.cpp
只定义了A::g
,main.cpp
没有尝试调用它(因为它不知道它的存在(。
因此链接器错误。
首先,请记住,main.cpp
看不到任何source.cpp
,所以它不知道其中声明/定义的实际void A::g()
函数!
main.cpp
看到的是一个命名空间A
using namespace B
。因此,当main.cpp
调用A::g()
时,编译器只能假设您引用void A::B::g()
- 因此将其标记为要链接的函数。
但是,正如链接器正确诊断的那样,您尚未为此函数提供定义- 因此无法解析。