Visual C:命名空间范围错误或晦涩难懂的功能?

Posted

技术标签:

【中文标题】Visual C:命名空间范围错误或晦涩难懂的功能?【英文标题】:Visual C: Namespace Scope Bug or Obscure Feature? 【发布时间】:2019-10-03 16:43:34 【问题描述】:

您将需要三个不同的文件:header.hsource.cppmain.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

代码由工具生成。

谢谢

【问题讨论】:

【参考方案1】:

当你这样做时:

  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::gmain.cpp 并没有尝试调用它(因为它不知道它的存在)。

因此出现链接器错误。

【讨论】:

我只是想在我的答案中添加关于A::B::C::f() 的内容,但不知道怎么做!你做得很漂亮 - 请给我点赞,先生!【参考方案2】:

首先,请记住main.cpp 看不到source.cpp,所以它不知道其中声明/定义的实际void A::g() 函数!

main.cpp 所做的 看到的是一个 命名空间 A,即using namespace B。因此,当main.cpp 调用A::g() 时,编译器只能假设您引用void A::B::g() - 从而将其标记为要链接的函数。

但是,正如链接器正确诊断的那样,您没有为此函数提供定义 - 所以它没有得到解决。

【讨论】:

以上是关于Visual C:命名空间范围错误或晦涩难懂的功能?的主要内容,如果未能解决你的问题,请参考以下文章

窗体头文件中的“错误 C2653:系统不是类或命名空间名称”,Visual C++

Visual Studio 2010 在编译 C++/CLI 项目时出现奇怪的错误

阻止 Visual Studio 将 using 指令放在命名空间之外

由于缺少未丢失的程序集引用,Visual Studio拒绝构建项目

晦涩难懂的shell命令

0-绪论