简体   繁体   English

在C ++中创建类时,将标准库头放在哪里?

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

Correct me if I am wrong, the #ifndef stuff in the beginning of C++ headers specifically help avoid code from being repeated? 如果我错了,请纠正我,C ++标头开头的#ifndef内容特别有助于避免代码重复?

So (according to best practice) where do I put basic library headers like < iostream > or < string > ? 因此(根据最佳实践),我应将诸如<iostream>或<string>之类的基本库头放在哪里?

Let me clarify the question with an example 让我用一个例子来澄清这个问题

Lets say I have a program that creates Employee classes and stores info about them..like their names or something 可以说我有一个程序可以创建Employee类并存储有关它们的信息。

  1. I have an int main() that uses std::cout ALOT to display info to console. 我有一个int main(),它使用std :: cout ALOT将信息显示到控制台。 It may even use hard coded string variables to store info into one of the classes (i know hard coding is bad just bear with me it will help clarify things for me) 它甚至可以使用硬编码的字符串变量来将信息存储到一个类中(我知道硬编码是不好的,请耐心等待,这将有助于我进行说明)

  2. I have a header called Employee.h with all my private variables..in this case the name of the employee.. and it also had the function declarations. 我有一个名为Employee.h的标头,其中包含我的所有私有变量..在这种情况下,名称为employee ..,并且还具有函数声明。 Lets pretend it uses a string data type in one of the constructors. 让我们假设它在构造函数之一中使用字符串数据类型。

  3. an Employee.cpp that does setting and getting...cool Lets also pretend it has some weird function that manipulates the Employee name (which is a string) and add like "yolo" in front of it..cool. 一个设置并获取... cool的Employee.cpp让我们还假设它具有一些怪异的功能,可操作Employee名称(这是一个字符串),并在其前面添加“ yolo”。 So this file will also require acsess to the < string > library 因此,此文件还需要访问<string>库

So far: all three of my files want to use the < string > header and only the main.cpp wants to use the < iostream > header. 到目前为止:我的所有三个文件都想使用<string>头,而只有main.cpp要使用<iostream>头。

My question(s): 我的问题:

Seems like the < string > header can be placed in the Eployee header and not the main.cpp and the program will compile and run just fine...but if i put it in the main and not the Employee header the compiler goes wild. 好像<string>头文件可以放在Eployee头文件中,而不是main.cpp中,程序将编译并运行得很好...但是,如果我将它放在main而不是Employee头文件中,则编译器将变得异常。 So should I include it in both main and header or just the header? 那么我应该在主标题和标头中都包含它还是仅在标头中包含它?

Does this best practice change if I make a second class called Companies that also uses the string library? 如果我制作第二个也称为字符串的公司,也称为Company,那么这种最佳实践会改变吗?

PS can somone please explain how common preprocessors link stuff..like why does the computer throw erros when < string > is only included in main but not the header...I thought this stuff was all linked together...Im dumb pls explain PS可以发出声音,请解释一下常见的预处理器如何链接东西。例如为什么当<string>仅包含在main中而不包含header时,计算机为什么会抛出错误……我认为这些东西都被链接在一起了……我愚蠢的解释

(I think i understand all the mumbo jumbo about obj files but then how doe preprocessors and compilers know that the header code isnt being repeated in both the class .cpp and the main .cpp? (我想我了解有关obj文件的所有庞然大物,但是预处理器和编译器如何知道在.cpp类和主.cpp类中都没有重复头代码?

Thank you for patience if you read through that, i also appreciate any help thrown this way towards a c++ noob like me. 感谢您的耐心阅读,我也非常感谢以此方式为像我这样的c ++新手提供的帮助。

According to the C++ standard: 根据C ++标准:

A translation unit is the basic unit of compilation in C++. 翻译单元是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. 它由单个源文件的内容以及直接或间接包含的任何头文件的内容组成,减去那些使用条件预处理语句忽略的行。

Note, the "indirectly included" wording. 注意,“间接包含”的措辞。 Any header to #include in another header is included in any source file that #include s that header. #include其他标头中的所有标头都包含在#include该标头中的任何源文件中。 So if you require it to be included in the header, that is if your header requires a definition not simply a declaration , #include it there. 因此,如果您要求将其包含在标头中,也就是说,如果标头需要一个定义而不只是一个声明 ,请在其中#include它。

A small of example of how a translation unit is generated: Initially we have our header. 生成翻译单元的一个小例子:最初,我们有标头。 Let's call it stdfoo.h (this is an example, you should avoid naming your own headers with std to avoid collision.) 让我们将其stdfoo.h (这是一个示例,应避免使用std命名自己的标头,以免发生冲突。)

#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

Let's include this in our project source main.cxx : 让我们将其包含在我们的项目源代码main.cxx

#include <stdfoo.h>

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

When we compile this, it gets run through the preprocessor into a translation unit. 当我们编译它时,它将通过预处理器运行到翻译单元中。 Let's take a look at what that generated unit may look like: 让我们看一下生成的单元可能是什么样的:

typedef long howl_t;
void foo();

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

The #include directive has expanded stdfoo.h in the translation unit so the compiler can look at the single translation unit and generate an object. #include指令在转换单元中扩展了stdfoo.h ,因此编译器可以查看单个转换单元并生成一个对象。

Let's change things up and give main.cxx a header, main.h . 让我们进行修改,并为main.cxx一个头文件main.h

#ifndef MAIN_H
#define MAIN_H

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

#endif // MAIN_H

Use it in our new main.cxx : 在我们新的main.cxx使用它:

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

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

The translation unit would look like: 翻译单元如下所示:

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

typedef long howl_t;
void foo();

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

Now say emit uses howl_t as an argument like so void emit(howl_t h) this would require either redeclaring howl_t, a dicey way to go, or including stdfoo.h in main.h 现在说一下, emit使用howl_t作为参数,例如void emit(howl_t h)这将需要重新声明howl_t(一种简单的方法),或者在main.h包含stdfoo.h

#ifndef MAIN_H
#define MAIN_H

#include <stdfoo.h>

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

#endif // MAIN_H

How does that translation unit look? 该翻译单元的外观如何?

typedef long howl_t;
void foo();

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

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

The preprocessor has expanded the #include inside of the #include d header. 预处理程序已在#include d标头中扩展了#include

Note whether or not #include <stdfoo.h> remains in main.cxx the translation unit would look the same due to the preprocessor handling the header guards, the second inclusion is simply discarded. 注意#include <stdfoo.h>是否仍保留在main.cxx ,由于预处理器处理标头防护,转换单元的外观将相同,仅将第二个包含项丢弃。

Now, as far as standard library headers, most of not all standard libraries guard against multiple inclusion, so you can #include then as frequently and often as your heart desires with no ill effect. 现在,就标准库头而言,并非所有标准库中的大多数都可以防止多重包含,因此您可以按自己的意愿频繁,频繁地#include ,而不会产生不良影响。 The resulting translation unit will only include it once for compilation. 生成的翻译单元将只包含一次以进行编译。 Do note this is not guaranteed with any other headers and including unguarded headers multiple times can yield very obscure looking errors as the duplicate declarations only exist in the translation unit. 请注意,使用任何其他标头不能保证这一点,并且多次包含无保护的标头可能会产生非常模糊的外观错误,因为重复声明仅存在于转换单元中。

So to answer your question, if your header requires a particular class or function to be included, #include it in the header. 因此,如果您的标头要求包含特定的类或函数,请在标头中#include ,以回答您的问题。 At that point, it is a stylistic choice whether you decide to #include it in the source file as well. 在这一点上,它是一个风格上的选择是否决定#include它在源文件中也是如此。 Some say do in case the header changes, some say do not to simplify code. 有人说万一标题改变了,有人说不简化代码。 That choice is really up to you. 该选择实际上取决于您。

If a header is not required in another header file, you are much better off only including it in each source file that requires it so that your code produces smaller translation units for compilation and in order to reduce namespace pollution. 如果另一个头文件中不需要头,则最好将其包括在需要它的每个源文件中,这样您的代码将生成较小的转换单元以进行编译,并减少名称空间污染。

However! 然而! This is not a hard and fast rule. 这不是一个硬性规定。 Some do it differently and arrange #include s into logical positions where they may be used or where certain headers are used in multiple source files to reduce code duplication. 有些使用不同的方法,并将#include安排在可以使用它们或在多个源文件中使用某些标头的逻辑位置,以减少代码重复。 Personally, I think of this arrangement added technical debt if code may be improved or refactored down the line and headers become orphaned. 就个人而言,我认为这种安排增加了技术负担,如果可以改进或重构代码,并且标头变得孤立的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM