【问题标题】:Using namespace to avoid name collisions使用命名空间避免名称冲突
【发布时间】:2012-05-24 07:27:58
【问题描述】:

我正在编译我使用的一个项目,这次是 VS2010,只是为了发现 windows.h 中的一个包含有一个 typedef INPUT,它与我已经拥有的代码中的导出 const 字符串发生冲突.

//winuser.h(行:5332)

typedef struct tagINPUT {
    DWORD   type;

    union
    {
        MOUSEINPUT      mi;
        KEYBDINPUT      ki;
        HARDWAREINPUT   hi;
    };
} INPUT, *PINPUT, FAR* LPINPUT;

//foo.h

//stuff here
extern FOO_DLL_API const string INPUT;

现在,我不在有问题的 .cpp 中使用 INPUT(而且我不拥有大部分代码),并试图将影响降到最低,我做了以下操作:

//myfile.cpp

#include <foo.h>
namespace windowsLib {    //I added this
#  include <windows.h>
}

using namespace windowsLib;

到目前为止,这种方法运行良好,但我想问您是否发现这种方法存在潜在问题,或者您是否有更好的建议。

编辑:

感谢所有关于为什么这是一个坏主意的 cmets 和解释。我从您的 cmets 得到的是我应该更改 foo.h 并将内容放入命名空间。但是,这样做会影响几十个文件,甚至更多,现在需要命名空间限定。

有没有办法在不触及所有这些文件的情况下以“正确的方式”做到这一点?

如果我是代码的所有者,我会进行此更改并完成它,但我必须提出一个解决方案并获得批准并分配给某人等。所以如果更改是更容易最小。

编辑 2:

我的最终建议是将班级分成两部分,如下所示:

//stub.cpp

#include <windows.h>

//Implementation of wrapper methods

//stub.h

class stub {
    //public wrapper methods
}

//myfile.cpp

#include <stub.h>
#include <foo.h>    

我接受 Benlitz 的回答,因为该建议还可以解决我目前面临的当前最小影响约束的问题。不过,我感谢大家的 cmets。

【问题讨论】:

    标签: c++ namespaces


    【解决方案1】:

    不仅语言不允许(假设标准头文件将包含在命名空间中),还有调用&lt;windows.h&gt;中声明的任何函数并发现链接器的问题将在命名空间windowsLib 中查找它们。

    就是不行!

    【讨论】:

      【解决方案2】:

      至少这似乎是个坏主意。

      1) 如果这实际上是您的代码,则添加命名空间没有任何好处,因为您在下一行有 using namespace windowsLib;INPUT 不会有歧义吗?

      2) 您可能包含使用来自windows.h 的内容并且不会使用正确符号的其他标头。想象一下,包含一个定义返回INPUT 的函数的标头。这会怎样?

      我建议你谨慎行事,重命名你的类型。

      【讨论】:

      • Yes INPUT 仍然模棱两可,但这个类尤其没有使用它。但是,当然,它可能会在将来使用。这个“INPUT”常量在所有地方都被使用(直到最近才使用的是 windows.h),所以改变它会很痛苦(对我来说不是,因为我不维护那个代码,但是永远痛苦) ,所以我更愿意向他们建议一个影响有限或可以防止未来出现问题的解决方案。
      • Bare INPUT 现在是模棱两可的(只要在使用时消除歧义,这是合法的,无论是作为 ::INPUT 还是作为 windowsLib::INPUT),而不是具有两个不同定义的符号(非法)。也就是说,坏主意。我推荐@Benlitz 的方法。
      • @cvoinescu 我不推荐这种方法。最好的方法是重命名变量。这只是滥用预处理器。
      • 当然,我的错。我误读了他的问题——我以为他说另一个标题是他无法控制的代码。
      【解决方案3】:

      正如其他答案中所解释的那样,这是一个坏主意。这是一个可以帮助您解决问题的想法:

      //myfile.cpp

      #define INPUT UnusedSymbol
      #include "foo.h"
      #undef INPUT
      
      #include "windows.h"
      

      这可能会起作用,因为 INPUT 是 foo.h 中的外部变量,因此只要您不在 myfile.cpp 中使用它,编译器和链接器都不会关心它。 UnusedSymbol 是一个虚拟名称,您可以编写源代码中未使用的任何名称。

      【讨论】:

      • 我测试了这个解决方案并且它有效。正如其他人指出的那样,我可能会推动在 foo.h 中进行修复,但这是一个更好的解决方案。
      • 嗯,是的,这个答案是针对“最小化影响”请求的。我还建议您将 foo.h 放入命名空间(当然是通过修改 foo.h 本身,而不是围绕 #include 编写命名空间声明)
      【解决方案4】:

      在 windows.h 周围放置一个命名空间对我来说听起来很危险。它可能会隐藏你需要的东西。除非你在下一行导入命名空间。

      我宁愿将命名空间放在 foo.h 周围:

      namespace fooLib {
      #include "foo.h"
      }
      
      using fooLib;
      

      我想这只是将问题从 OS 代码转移到 foo 代码,但这对我来说似乎更安全。

      另一种方法可能是围绕 foo 构建一个包装器,该包装器调用 foo 函数并在单独的小包装器库中返回 foo 全局变量。一个不需要 windows.h 的。您可以将此包装器放入命名空间中以防止这种情况再次发生。

      我在这里假设您没有能够重命名 foo.h 中的内容或将 fooLib 命名空间放在 foo.h 中的内容周围。

      如果您可以触摸foo.h,最好在 foo.h 中重命名 INPUT 或将 foo.h 内容放在它自己的命名空间中。我认为fooLib 命名空间会有很大(明显)的好处。

      【讨论】:

      • 我正在研究我的老问题。您关于围绕 foo 构建包装器的评论与我最终向​​代码所有者提出的建议接近。由于使用 foo 这样做会很痛苦,因此我将 windows.h 依赖项封装在一个单独的文件中并提供了一个包装类。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 1970-01-01
      • 2023-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 2023-03-11
      相关资源
      最近更新 更多