源文件中的私有命名空间

Private namespace in source files

本文关键字:命名空间 源文件      更新时间:2023-10-16

我对私有方法有疑问&功能。假设我有一些不需要在类中的实用工具方法。但这些功能需要调用我不想暴露给用户的其他功能。例如:

Suspect.h

namespace Suspect {
  /**
  *  brief This should do this and that and more funny things.
  */
  void VerbalKint(void);  // This is for you to use
}

Suspect.cpp

namespace Suspect {
  namespace Surprise {
    /**
    * brief The user doesn't need to be aware of this, as long 
    *        the public available VerbalKint does what it should do.
    */
    void KeyserSoze(void) {
      // Whatever
    }
  } // end Surprise
  void VerbalKint(void) {
    Surprise::KeyserSoze();
  }
}

这个布局是有效的。当包含Suspect.h时,只有VerbalKint可见。这也可以通过使用一个类并将VerbalKint标记为静态来实现:

class Suspect {
public:
  // Whatever
  static void VerbalKint(void);
private:
  static void KeyserSoze(void);
};

我想知道这两种方法有什么不同。一个比另一个更好(更快,更容易维护)吗?

你是怎么想的?

如果函数是'free',则应该在*.cpp中使用匿名命名空间:

namespace Suspect {
namespace Surprise {
namespace {
    void KeyserSoze(void) {
      // Whatever
    }
} // end anon
} // end Surprise
} // end Suspect

甚至:

namespace {
    void KeyserSoze(void) {
      // Whatever
    }
} // end anon

这使它远离客户端,这样他们就不能访问,依赖,或者在链接时与你的导出相冲突。它还可以避免不必要的声明,减少编译时间,如果定义可见,还可以减少链接时间或二进制大小。最后,它使它成为私有的,这样他们就不能依赖它,您也不需要为他们的使用维护它。如果您选择的话,您仍然可以将这些传递给外部世界(在KeyserSoze()的情况下是函数指针)。

在其他时候,最好在类中声明私有成员函数,然后在*.cpp中定义它(如果可能)。通常,当您需要与类建立更紧密的关系时(例如,当您需要访问某些成员时),您将选择这种方法。你说在问题中不是这样的,但我只是重申什么时候应该使用私有成员。

最好的方法是在Suspect.cpp的一个未命名的名称空间中定义所有的帮助函数,而不是在Suspect::Surprise的名称空间中。

在你的例子中,这将是:

namespace{
void KeyserSoze(){ ... };
}

您可以在Suspect.cpp中简单地调用KeyserSoze,而不需要任何命名空间说明符。

您可以在这里找到更多信息:未命名/匿名名称空间与静态函数

另一种选择是将KeyserSoze声明为static,但标准不建议这样做。c++标准在7.3.1.1节未命名的命名空间第2段中读到:

在命名空间范围内声明对象时不建议使用static关键字,unnamed-namespace提供了一个更好的选择

实际上,即使当你没有在任何头文件中声明该函数时,它对眼睛是不可见的;如果用户编写声明,它仍然是可用的。

在c++中,隐藏在文件级声明的符号的机制是:

  • (全局)变量和函数的static
  • namespace { ... }(匿名名称空间)用于任何您想要的内容(更一般,更详细)
例如:

// Suspect.cpp
namespace Suspect {
    static void KeyserSore() {}
    void VerbalKing() { KeyserSore(); }
}

在类和命名空间中添加内容的主要区别是不能在另一个头文件中向类添加额外的静态函数。

:a.h

namespace Fred {
   void Somefunc();
}

b.h

namespace Fred {
   void Anotherfunc();
}

可以工作,尽管a和b都不知道对方对其名称空间做了什么。这可能会导致如下问题:

刘昀

namespace Fred {
   void Thirdfunc();
}

d.h

namespace Fred {
   bool Thirdfunc();
}

一切都很好,直到你开始运行程序…

虽然不是不可能,但对于类来说可能性要小得多。

在您的示例中,只有一个源文件,您可能还想考虑使用匿名命名空间,因为它将声明限制在文件范围内,因此文件以外的人不能意外地访问它们(或与它们冲突)。