如果前者仅提供后者定义的声明,我是否应该在关联的 cpp 文件中包含标头?

问题描述 投票:0回答:3

考虑一个包含以下内容的

foo.cpp
文件

#include "foo.hpp"
int foo() {
    return 7;
}

及其关联的标头

#pragma once
int foo();

显然需要后者来了解以下

main
函数是否存在
foo
:

#include <iostream>
#include "foo.hpp" // to make the name `foo` available

int main() {
    std::cout << foo() << std::endl;
}

然而,

#include "foo.hpp"
似乎是多余的。我有什么理由应该保留它吗?


我在我工作的代码库中看到了这种做法,但我想开源中有很多可用的示例。例如,作为随机选取的示例,请查看

src/builtin_builtin.h
代码库中的
src/builtin_bultin.cpp
fish-shell
:前者在包含防护旁边,具有 只是

  1. 一个
    #include
  2. 两个类声明,
  3. 和函数声明。

可以将 2 放入 fwd 标头中,将其与 1 一起包含在 cpp 文件中,然后 cpp 文件将不再需要包含自己的标头。

c++ include header-files declaration translation-unit
3个回答
3
投票

C++ 按线性顺序处理文件。如果您的 .cpp 文件调用同一 .cpp 文件中的其他方法,则需要使用定义来继续调用,否则您需要 .hpp 中的声明。对于两个相互递归的函数,您确实需要至少一个预先声明。

此外,拥有可用的类声明意味着编译器可以警告不匹配(由于重载,不适用于自由函数声明)


2
投票

从其实现文件 (

fpp.hpp
) 中包含标头 (
fpp.cpp
) 的一些原因:

  1. 如果您在

    foo.hpp
    中包含 foo.cpp
    first
    ,则
    foo.cpp
    的编译将充当
    foo.hpp
    是否为 self-contained 的测试,这意味着无需先包含任何其他内容即可成功编译。 Google C++ 编码指南特别建议首先包含关联的标头

  2. 对于

    foo.hpp
    来说,声明
    foo.cpp
    导出的所有内容,并且对于
    foo.cpp
    中的其他所有内容都具有 内部链接,这是一个很好的做法,以免污染全局命名空间。 GCC 选项
    -Wmissing-declarations
    将报告与该实践的偏差,但仅当
    foo.cpp
    包含
    foo.hpp
    时才有效。

  3. 有时(事实上,经常),需要包含

    foo.hpp
    ,以便
    foo.cpp
    能够编译。最常见的是,
    foo.hpp
    定义了
    foo.cpp
    需要的类型,但也可能由于在定义之前使用而需要函数声明。我建议始终如一地这样做,而不是试图推断每种情况是否有必要。

  4. 有时,编译器可以诊断声明和定义之间的不匹配。我见过的一个令人讨厌的例子是一个标头声明了全局

    int x
    但实现文件定义了
    long x
    。浪费一天时间调试该错误,我预测您将决定此后每次都包含关联的标头!

最后,没有充分的理由包含关联的标头。特别是,省略 include 几乎不会对编译时间产生可测量的差异。有方法可以通过重组标头依赖性(例如,使用前向标头)来显着提高编译时间,但这不是其中之一。

致谢:国际收支平衡表在评论中指出了第 1 点。 MSalters 的回答 注意到第 3 点和第 4 点。


0
投票

我刚刚发现有一个关于它的核心指南,

SF.5:
.cpp
文件必须包含定义其接口的头文件

其中确实提到了其他答案的一些要点。

© www.soinside.com 2019 - 2024. All rights reserved.