C++ 详细命名空间、匿名方法、私有方法、类方法、pimpl 方法、友元类方法

tha*_*san 2 c++ namespaces friend-class

请耐心听我说。我试图弄清楚你在什么时候划清界限,将辅助方法放入匿名、详细命名空间、私有、创建 pimpl 或友元类中。

这是我的看法..请让我知道您的想法。

所以,如果我有 foo.hpp foo.cpp

我有一些自由函数bar,它们不访问 中的任何数据成员foo,而且没有客户端需要知道这些自由函数,只有 的foo.cpp方法需要它们,只需将它们直接放入 foo.cpp 中的匿名命名空间中即可完成。

但是,如果bar需要访问 foo 的数据成员,我们可以将barfoo 设为私有方法。但这意味着即使 foo 的客户端并不真正关心bar,每次bar更改,我们都会重新编译。

(这部分我有点模糊):但是,在这种情况下至少使用详细名称空间可以帮助 foo.hpp 的读者不必费心查看bar,因为他们实际上不需要知道它。这是详细命名空间约定的一般用例吗?

现在,如果我们有一堆 bar_1、bar_2...bar_n 并且它们相互关联并且需要访问数据成员,我可以为bazfoo 创建一个友元类,并将bars 放在那里。

然而,如果我真的担心编译时间和隐藏界面,我可以求助于 pimpl (这部分再次非常模糊,通常如果我看到这一点,警报就会响起并告诉我设计中出现了问题)。

你的想法...

小智 5

正如有人之前评论的那样,最好提供一个包含您的问题的代码示例,因为您描述的概念非常抽象和复杂。

以下是我对您想了解更多信息的项目的看法:私有方法、私有实现、未命名命名空间非成员函数、“命名”命名空间中的非成员函数以及友元非成员函数。

私有方法:首先,您必须在类声明中声明这些方法,这样即使您的类之外没有人可以调用它们,它们的原型也将是公开可见的。这有点无意义。您应该在两种情况下使用这些方法:

  1. 您需要在此方法的实现中访问您的类私有的内容。
  2. 您正在使用 NVI 惯用法实现虚拟方法。

私有实现:您应该使用它来隐藏类的实现细节。又称其数据成员。我经常做的一件事是在类头文件中转发声明我的 pImpl 类型,并使我的类成为 cpp 文件中私有实现类的类友元。

未命名命名空间非成员函数:这些或多或少相当于在实现文件中使用 static 关键字声明的非成员函数。你应该尽可能多地拍摄这些。一个好的经验法则是,所有非虚拟私有方法都应该可以实现为在未命名命名空间中声明的非友元、非成员函数。这样做的优点是它迫使您在实现此类函数时使用类的公共接口。一个重要的警告:永远不要在头文件中使用未命名的名称空间。(.h 或 .hpp)如果这样做,则每次包含该文件时,这些文件中的每个原型都会有一个唯一的符号。这会很快导致符号混乱。

命名空间内的非成员非友元函数:大多数时候,当您想要向类添加服务或提供未绑定到类的辅助函数时,您将使用这些函数。这些函数的优点是它们仅使用类的公共接口。充分利用这些方法的一个很好的例子是为您的类实现运算符。假设您有“A”级和“B”级。并且您想要将 A 的实例添加到 B 的实例。传递性规则表明您也可以将 B 添加到 A 并获得相同的结果。如果将运算符+设置为非成员,则无需修改任何一个类即可实现此功能。如果您将其作为公共方法执行,则必须在两个类中执行此操作。如果您想了解有关该主题的更多信息,我会向您推荐 Scott Meyers“Effective C++”。

友元非成员函数:您应该尽可能避免这些。原因是它们的实现依赖于类的私有细节。否则你为什么要和他们成为朋友呢?人们普遍认为,类的私有实现细节可以随时更改,这可能会破坏您的功能或更糟:使其以与预期不同的方式运行。

现在你已经知道了,当你有虚拟方法通过 NVI 惯用法声明时,使用私有方法,将你的数据成员放在私有实现中,在未命名命名空间下的实现文件中声明所有非虚拟私有方法,声明公共服务尽可能使用非成员非友元函数并且不使用任何友元非成员函数。