支持函数声明应该去哪里
Where should support function declarations go?
>我有一个.cpp源文件,其中包含一些需要公开访问的函数和一些仅在此源文件中使用的支持函数。
我一直将所有这些函数声明放在头文件中,因为我个人发现在一个地方查看类提供的所有内容很有用。但是,我想指出这些函数是否供内部使用,类似于 private
访问修饰符,但不使用类(它们是独立的函数(。
一些可能的解决方案是:
- 将私有声明放在源文件中。
- 将私有声明放在单独的标头中。
这两种解决方案都将公共和私有功能拆分为单独的文件,我想避免这样做。
如果函数不打算供公众使用,则不应将 放入标头中。将它们放入使用它们的源文件中。
要完全隐藏这些功能,使其不被在源文件外部使用,通常执行以下操作之一:
- 函数声明为
static
。 - 函数被放入一个未命名的
namespace
中。
后者被认为是可取的。实际上,C++标准 7.3.1.1 规定:
有关未命名命名空间在命名空间作用域中声明对象时,不推荐使用 static 关键字,unnamed-namespace 提供了一个更好的替代方法。
与静态的更多讨论,请参阅未命名/匿名命名空间与静态函数以及相应的 comp.lang.c++.moderated 线程。
如果私有函数仅在单个源文件中使用,则不需要任何额外的头文件。只需将功能标记为static
或使用匿名namespace
即可。
如果可以从许多源文件中使用这些函数,请在特殊namespace
的单独头文件中声明它们。这是我的建议。
支持函数声明应该去哪里?
他们不必去任何地方。将它们设为静态并保存在源文件中。如果它们仅在单个源文件中使用,则无需在任何标头中提出声明。
你没有提到这些"函数"是否是类的成员,但我假设它们是。如果是这样,我建议您查看"痘痘成语"。基本上,这意味着将要保持私有的全部或大部分内容放入单独的类中,然后在类声明中仅具有指向该类实例的指针。例如:
class MyClass
{
// ... some stuff
private:
SecretObject obj_;
int hiddenCall();
};
成为
class MyClassImpl;
class MyClass
{
private:
MyClassImpl* impl_;
};
那么这个想法是,你的implemntation类的所有声明和定义都将进入你的.cpp文件,该文件对编译单元以外的任何东西都隐藏了它。这种方法具有许多重要的优点:
- 隐藏实现,以便公开可用的标头不会泄露太多实现。
- 可以通过删除标头中的依赖项来提高编译速度 - 如果标头包含很多,则很重要。
- 可用于将客户端代码与不需要构建的库(如数据库 API 等("隔离"出来。
有许多缺点:
- 如果代码隐藏在 cpp 文件中,可能会使单元测试更加棘手。就我个人而言,我发现更好的解决方案是拥有一个单独的私有头文件和实现文件,以便您可以控制代码的客户端获取的内容,但测试工具仍然可以对其进行充分测试。您可以简单地在 cpp 文件中包含
MyClassImpl
标头,但不要将其包含在MyClass
标头中 - 这会破坏对象。 MyClass
和MyClassImpl
之间的间接寻址可能令人厌烦编码/管理。
不过,一般来说,这可能是实现您想要达到的目标的最佳方式。查看Herb Sutter的文章以获得更深入的解释。
另一方面,如果您谈论的是与类没有直接关系的自由函数,那么我会将它们放在 cpp 文件的未命名命名空间中。例如:
namespace {
// Your stuff goes here.
};
同样,如果您采用这种方法,您会遇到如何访问这些函数的单元测试问题,但如果这确实是一个问题,则可以通过创建特定的命名空间、条件编译等来解决此问题。不理想,但有可能。
- Visual Studio中的函数声明和函数定义问题
- 为什么函数声明中允许 const?
- 如果 x.h 仅由函数声明组成,为什么有必要在 x 中包含 x.h.cpp
- * 和 ** 在 C++ 函数声明中是什么意思?
- 构造函数/函数声明参数列表中的统一初始化
- 在将函数声明为友元时,尖括号的含义是什么?
- 为什么转换函数声明不需要至少一个定义类型说明符
- 如何正确编写指针函数声明?
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- 为什么要将函数声明和定义放在单独的文件中
- 为什么系统日志有两个不同的函数声明?
- 我如何获取数组的大小,以便我可以从函数声明所述数组
- 使用 enable_if 在按值传递与按引用传递之间更改函数声明
- JavaScript 中的一等函数和 C++ 中的函数声明
- C++ 通过函数声明后初始化向量
- VS2017 #error: : snprintf 的宏定义与标准库函数声明冲突
- C++ 17 个友元函数声明和内联命名空间
- MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的好友
- 将派生类的构造函数声明为父类的友元
- 用于从 ANSI 字符串转换为 std::basic_string <TCHAR>的正确函数声明