【问题标题】:Scope of using namespace versus using namespace closure使用命名空间与使用命名空间闭包的范围
【发布时间】:2020-01-16 15:58:16
【问题描述】:

我试图理解为什么在我使用命名空间而不是显式声明命名空间附件时我的函数存在歧义。

Book.h 头文件:

#ifndef MYBOOK_BOOK_H
#define MYBOOK_BOOK_H 

namespace mybook
{
    void showTitle();
    void showTableOfContents();
}

#endif

我的 implmenetation 文件导致歧义错误: Book.cpp

#include "Book.h"
#include <iostream>
#include <cctype>
#include <cstring>

using namespace std;
using namespace mybook;

void showTitle() {
    cout << "The Happy Penguin" << endl;
    cout << "By John Smith" << endl;
}

void showTableOfContents() {
     cout << "Chapter 1" << endl;
     cout << "Chapter 2" << endl;
}

我的实现文件没有歧义错误: 书本.cpp

#include "Book.h"
#include <iostream>
#include <cctype>
#include <cstring>

using namespace std;

namespace mybook {

   void showTitle() {
       cout << "The Happy Penguin" << endl;
       cout << "By John Smith" << endl;
   }

   void showTableOfContents() {
        cout << "Chapter 1" << endl;
        cout << "Chapter 2" << endl;
   }
}

我认为 Book.cpp 的第一个场景应该可以工作,因为通过在开头声明 using namespace mybook 表示我现在要实现我在头文件中定义的函数。但是我得到了“错误'showTitle'的错误:对重载函数的模糊调用可能是'void showTitle(void)或void mybook :: showTitle(void)'”,对于我的其他函数showTableOfContents也是如此。为什么在第一种情况下使用命名空间 mybook 不起作用?

【问题讨论】:

  • 永远不要使用“使用命名空间标准”。你不应该试图弄清楚如何让它发挥作用,而应该摆脱这种做法。
  • 并且不要使用cstring等C头文件。使用字符串和 C++ 中的适当工具。
  • Eric 评论的一些背景:stackoverflow.com/questions/1452721/… 请注意,有些人不同意您应该永远使用using namespace std的想法。
  • @Rosme 虽然首选std::string 而不是C 字符串是一个好建议,但通常不使用C 头文件并不是一个好建议。例如,使用来自&lt;cmath&gt;&lt;cstdint&gt;&lt;cstddef&gt; 和许多其他的东西没有任何问题。在 OP 的情况下(尽管它目前未使用)&lt;cctype&gt; 也有有效用途,因为它提供的大多数功能都没有 C++ 等价物。
  • @walnut 真的。我不应该那样说。

标签: c++ namespaces declaration definition name-lookup


【解决方案1】:

我认为 Book.cpp 的第一个场景应该可以工作,因为通过在开头声明 using namespace mybook 表示我现在要实现我在头文件中定义的函数。

那是你不正确的地方。 using namespace mybook; 表示您正在使用来自 mybook 的名称,而不是您正在为 mybook 定义/添加名称。要在 mybook 中定义名称,您需要打开命名空间并将定义放入其中,就像您在第二个示例中所做的那样。

【讨论】:

    【解决方案2】:

    这些定义

    using namespace std;
    using namespace mybook;
    
    void showTitle() {
        cout << "The Happy Penguin" << endl;
        cout << "By John Smith" << endl;
    }
    
    void showTableOfContents() {
         cout << "Chapter 1" << endl;
         cout << "Chapter 2" << endl;
    }
    

    在全局命名空间中声明两个函数。

    所以现在您在全局命名空间和命名空间mybook 中有四个函数,它们具有相同的声明并且由于包含了 using 指令

    using namespace mybook;
    

    非限定名称查找找到所有四个函数。因此,编译器会报告歧义。

    如果要定义在命名空间 mybook 中声明的函数,则必须编写

    using namespace std;
    using namespace mybook;
    
    void mybook::showTitle() {
        cout << "The Happy Penguin" << endl;
        cout << "By John Smith" << endl;
    }
    
    void mybook::showTableOfContents() {
         cout << "Chapter 1" << endl;
         cout << "Chapter 2" << endl;
    }
    

    那就是你需要使用限定名。

    来自 C++ 17 标准(10.3.1.2 命名空间成员定义)

    2 命名命名空间的成员也可以通过显式限定名称在该命名空间之外定义 (6.4.3.2) 已定义,前提是要定义的实体已在 命名空间和定义出现在声明点之后 在包含声明命名空间的命名空间中。

    和(7.3.4 使用指令)

    3 using-directive 不会向声明区域添加任何成员 它出现在哪里

    注意,由于不合格的名称查找引起的歧义。

    如果您使用限定名称查找,那么编译器会在全局命名空间(在这种情况下程序将成功执行)或命名空间mybook(在这种情况下编译器或链接器会报告错误)中找到声明的函数没有定义函数)。

    这是一个演示程序。

    #include <iostream>
    
    namespace mybook
    {
        void f1();
        void f2();
    }
    
    using namespace mybook;
    
    void f1() { std::cout << "::f1();\n"; }
    void f2() { std::cout << "::f2();\n"; }
    
    int main() 
    {
        ::f1();
        ::f2();
    
        return 0;
    }
    

    它的输出是

    ::f1();
    ::f2();
    

    如果你愿意写

    mybook::f1();
    mybook::f2();
    

    然后会出现函数未定义的错误。

    【讨论】:

    • 感谢这些例子帮助我向我说明了我在哪里理解错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多