在 C++ 中创建 类 时,我的标准库 headers 放在哪里?

Where to put my standard library headers when creating classes in C++?

如果我错了请纠正我,C++ header 开头的#ifndef 东西特别有助于避免代码重复?

那么(根据最佳实践)我应该把基本库 header 放在哪里,比如 < iostream > 或 < string >?

让我用一个例子来澄清这个问题

假设我有一个程序可以创建员工 classes 并存储关于他们的信息..比如他们的名字或其他东西

  1. 我有一个 int main(),它使用 std::cout 大量向控制台显示信息。它甚至可以使用硬编码字符串变量将信息存储到 classes 之一(我知道硬编码不好,请耐心等待,这将有助于为我澄清事情)

  2. 我有一个名为 Employee.h 的 header 和我所有的私有变量..在这种情况下是员工的名字..它还有函数声明。假设它在其中一个构造函数中使用字符串数据类型。

  3. 一个 Employee.cpp 做设置和获取...很酷让我们假装它有一些奇怪的功能来操纵员工姓名(这是一个字符串)并添加像 "yolo" 在它前面..很酷。因此,此文件还需要访问

到目前为止:我的所有三个文件都想使用 header,只有 main.cpp 想使用 header .

我的问题:

似乎可以将 header 放在 Eployee header 而不是 main.cpp 中,程序将编译并且 运行 就好了。 .但是如果我把它放在 main 而不是 Employee header 中,编译器就会疯狂。那么我应该将它包含在 main 和 header 中还是只包含在 header?

如果我创建第二个 class 也使用字符串库的名为 Companies 的公司,这种最佳做法是否会改变?

P.S。请有人解释一下预处理器 link 是多么常见的东西..比如为什么当 只包含在 main 而不是 header 时计算机会抛出错误...我认为这些都是 link在一起...我很笨请解释

(我想我理解所有关于 obj 文件的胡言乱语,但是 doe 预处理器和编译器如何知道 header 代码在 class .cpp 和 main . cpp?

如果您通读了这篇文章,感谢您的耐心等待,我也非常感谢以这种方式对像我这样的 C++ 新手提供的任何帮助。

根据C++标准:

A translation unit is the basic unit of compilation in C++. It consists of the contents of a single source file, plus the contents of any header files directly or indirectly included by it, minus those lines that were ignored using conditional preprocessing statements.

注意,"indirectly included" 的措辞。另一个 header 中的任何 header 到 #include 都包含在 #include 是 header 的任何源文件中。因此,如果您要求它包含在 header 中,也就是说,如果您的 header 需要一个 定义 而不仅仅是一个 声明 , #include 在那里。

关于如何生成翻译单元的一个小例子:最初我们有 header。我们称它为 stdfoo.h(这是一个示例,您应该避免使用 std 命名您自己的 header 以避免冲突。)

#ifndef STD_FOO_ // here is our header guard
#define STD_FOO_

typedef long howl_t;
void foo();

#endif // STD_FOO_ close the header guard at the end

让我们将其包含在我们的项目源代码中 main.cxx:

#include <stdfoo.h>

int main {
    foo();
    return 0;
};

当我们编译它时,它会通过预处理器 运行 进入翻译单元。让我们看看生成的单元可能是什么样子:

typedef long howl_t;
void foo();

int main {
    foo();
    return 0;
};

#include 指令在翻译单元中扩展了 stdfoo.h,因此编译器可以查看单个翻译单元并生成 object。

让我们改变一下,给main.cxx一个header,main.h

#ifndef MAIN_H
#define MAIN_H

class BarkBark {
    BarkBark() {}
    void emit();
};

#endif // MAIN_H

在我们的新 main.cxx 中使用它:

#include "main.h"
#include <stdfoo.h>

int main {
    BarkBark woof;
    woof.emit();
    foo();
    return 0;
};

翻译单元看起来像:

class BarkBark {
    BarkBark() {}
    void emit();
};

typedef long howl_t;
void foo();

int main {
    BarkBark woof;
    woof.emit();
    foo();
    return 0;
};

现在说 emit 使用 howl_t 作为参数,像这样 void emit(howl_t h) 这将需要重新声明 howl_t,这是一种冒险的方式,或者包括 stdfoo.hmain.h

#ifndef MAIN_H
#define MAIN_H

#include <stdfoo.h>

class BarkBark {
    BarkBark() {}
    void emit(howl_t h);
};

#endif // MAIN_H

那个翻译单元看起来怎么样?

typedef long howl_t;
void foo();

class BarkBark {
    BarkBark() {}
    void emit();
};

int main {
    howl_t aroooooo = 0;
    BarkBark woof;
    woof.emit(aroooooo);
    return 0;
};

预处理器扩展了 #included header 中的 #include

请注意 #include <stdfoo.h> 是否保留在 main.cxx 中,由于预处理器处理 header 守卫,翻译单元看起来是一样的,第二个包含被简单地丢弃。

现在,就标准库 header 而言,并非所有标准库中的大多数都可以防止多重包含,因此您可以 #include 然后随心所欲地频繁和经常地进行,没有恶意影响。生成的翻译单元将只包含一次编译。请注意,任何其他 headers 都不能保证这一点,并且多次包含不受保护的 headers 可能会产生非常模糊的错误,因为重复声明仅存在于翻译单元中。

因此,为了回答您的问题,如果您的 header 需要包含特定的 class 或函数,#include 将其包含在 header 中。在这一点上,是否决定在源文件中也 #include 它是一种风格选择。有人说万一 header 发生变化,有人说不要简化代码。这个选择真的取决于你。

如果另一个 header 文件中不需要 header,最好只将它包含在需要它的每个源文件中,以便您的代码生成较小的编译单元和为了减少命名空间污染。

但是!这不是硬性规定。有些人的做法不同,将 #include 安排到可能使用它们的逻辑位置,或者在多个源文件中使用某些 header 的位置以减少代码重复。就个人而言,我认为这种安排会增加技术债务,如果代码可能会被改进或重构,并且 headers 变得孤立。