#include 语句应该驻留在哪里?

发布于 2024-10-04 07:29:27 字数 1555 浏览 1 评论 0原文

作为一个回归 C++ 的新手,我正在尝试对 #include 方法进行排序。

我遵循以下示例中详细说明的一组特定准则。到目前为止,这对我来说已经成功了(整个项目不断编译:)),但我担心将来可能会遇到问题,因此我的问题是 - 这是正确的方法吗?还有更好的吗?解释它的底层逻辑是什么?

考虑以下示例:

Father.h

#pragma once
class Father
{
    // Some implementation
};

ClassA.h

#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
    StructC struct_c_obj;
    ClassB class_b_obj;
    // Some implementation
};

ClassA.cpp

#include "Father.h"
#include "ClassB.h"
#include "StructC.h"
// Some implementation

的类

ClassB.h 和 ClassB.cpp
不包含StructC.h

struct StructC {
    // Some implementation
};

我遵循以下准则:

  • 所有 *.h 均以 #pragma Once 声明
  • 如果 ClassA 继承自类 Father,则它必须将其包含在 *.h 和 *.cpp 文件中
  • 如果 ClassA 使用 ClassB(并且在类的作用域中声明了一个 ClassB 变量),则它有一个class ClassB; ClassA.h 中的声明和 ClassA.cpp 中的 #include "ClassB.h"
  • 如果 ClassA 使用 StructC(并且在类的作用域中声明了一个 StructC 变量) ),它必须将其包含在 ClassA.h 和 ClassA.cpp 中
  • 如果 ClassA 使用 ClassD 或 StructE 但仅在 ClassA.cpp 文件中,那么它应该仅在其中包含它们

这可能是一组笨拙的指南,对基本逻辑,所以我可能会生气...来吧,我正在尝试在这里学习...:)

更新:

  • 正如下面一些人所写的,我在示例中遇到了错误 - 仅当 ClassA 具有指向 ClassB 的指针或引用,而不是具有简单的 ClassB 数据时,才可以在 ClassA 中使用 ClassB 的前向声明 -成员。

As a returning newbie to C++, I'm trying to sort the #include methodology.

I'm following a certain set of guidelines I detail below the following example. So far this has worked out for me (the entire project keeps compiling :) ), but I'm worried I may encounter problems in the future, therefore my questions are - is this a correct methodology? Is there a better one? What's the underlying logic that explains it?

Consider the following example:

Father.h

#pragma once
class Father
{
    // Some implementation
};

ClassA.h

#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
    StructC struct_c_obj;
    ClassB class_b_obj;
    // Some implementation
};

ClassA.cpp

#include "Father.h"
#include "ClassB.h"
#include "StructC.h"
// Some implementation

ClassB.h and ClassB.cpp
A class without includes

StructC.h

struct StructC {
    // Some implementation
};

I follow these guidelines:

  • All *.h are headed by a #pragma once declaration
  • If ClassA inherits from class Father, it must include it in both *.h and *.cpp file
  • If ClassA uses ClassB (and has a ClassB variable declared at the class's scope), it has a class ClassB; decleration in ClassA.h and an #include "ClassB.h" in ClassA.cpp
  • If ClassA uses StructC (and has a StructC variable declared at the class's scope), it has to include it in both ClassA.h and ClassA.cpp
  • If ClassA uses ClassD or StructE but only in the ClassA.cpp file, then it should include them only there

This is probably a clumsy set of guidelines with little understanding of the underlying logic, so I'm probably going to get some wrath... Bring it on, I am trying to learn here... :)

UPDATES:

  • As some have written below, I have an error in the example - you can use a forward declaration of ClassB in ClassA only if ClassA has a pointer or a reference to ClassB and not if it has a simple ClassB data-member.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

恬淡成诗 2024-10-11 07:29:27

这些是我个人遵循的准则:

  • 尽可能使用前向声明而不是包含。在您的情况下,ClassA 包含一个ClassB,因此需要#include "ClassB.h"。如果 ClassB 类型仅通过指针或引用出现在文件中,则前向引用就足够了
  • 使头文件“自足”:编译永远不应该依赖于包含的顺序,并且包含文件应包含/转发声明需要解析的所有内容
  • 为了确保遵守前面的准则,请始终在 ClassA.cpp 中首先包含 ClassA.h,并使用任意顺序对于以下包含(我使用字母顺序排序)

关于其他方面:

  • #pragma 是非标准的,更喜欢 包含防护
  • 请记住,您永远不应该转发声明标准类型:如果 std::string 出现在您的头文件中,则您已经#include
  • 如果您最终得到的头文件包含一百万个其他文件,您可能需要查看 pimpl 惯用法 来减少依赖性(本文还包含有关头文件的其他一些指南)。

These are the guidelines I personally follow :

  • Prefer forward declarations instead of includes whenever possible. In your case, ClassA contains a ClassB so a #include "ClassB.h" is required. Had the ClassB type only appear in the file by pointer or reference, a forward reference would have been sufficient
  • Make header file "self sufficient" : compilation should never depend on the order of inclusions, and an include file should include / forward declare all it needs to be parsed
  • To ensure that the preceding guideline is respected, always include ClassA.h first in ClassA.cpp, and use an arbitrary ordering for the following includes (I'm using alphabetical sort)

Regarding other aspects :

  • #pragma is non standard, prefer include guards
  • Keep in mind that you should never forward declare standard types : if std::string appears in your header file, you have to #include <string>
  • If you end up with a header file which includes a million other files, you might want to look into the pimpl idiom to reduce dependencies (this article also contains several other guidelines regarding header files).
久随 2024-10-11 07:29:27

当 ClassA 具有此类型的数据成员时,不要使用 ClassB 的前向声明。
当它有一个指向 ClassB 的指针时,就可以使用它,如下所示:

#pragma once 
#include "Father.h" 
#include "StructC.h" 
class ClassB; 
class ClassA : public Father 
{ 
    StructC struct_c_obj; 
    ClassB *class_b_obj; 
    // Some implementation 
}; 

Don't use forward declaration of ClassB, when ClassA has a data member of this type.
It's OK to use it, when it has a pointers to ClassB, as in:

#pragma once 
#include "Father.h" 
#include "StructC.h" 
class ClassB; 
class ClassA : public Father 
{ 
    StructC struct_c_obj; 
    ClassB *class_b_obj; 
    // Some implementation 
}; 
迷雾森÷林ヴ 2024-10-11 07:29:27

#pragma Once 是非标准的(但得到广泛支持),因此您可能/可能不想使用 #ifdef 防护来代替。

至于您是否需要#include任何特定标头,这取决于情况。如果代码只需要前向声明,请务必通过前向声明类型来避免导入。

除了模板之外,我认为将长函数定义放在头文件中可能不太漂亮。

话虽如此,我认为 ClassA.h 实际上应该包含 ClassB.h 因为 ClassA.h 的任何用户(大概是使用 ClassB.h >ClassA)必须有ClassB.h。好吧,如果它正在做诸如分配之类的事情。

#pragma once is non-standard (but widely supported), so you may/may not want to use #ifdef guards instead.

As for whether you need to #include any particular header, it depends. If the code only requires a forward declaration, by all means avoid the import by just forward declaring the type.

And with the exception of template stuff, I think it is probably not-too-pretty to place long function definitions in the header files.

Having said that, I think that ClassA.h should actually include ClassB.h because any user of ClassA.h (presumably to use ClassA) will have to have ClassB.h. Well, if it is doing anything like allocating it.

牛↙奶布丁 2024-10-11 07:29:27

我从 Python 中得到的一件事(因为这是绝对的要求)是“将其导入(包含)到使用它的模块中”。这将使您在有或没有定义时摆脱麻烦。

One thing I've garnered from Python (because it's an absolute requirement there) is "import (include) it in the modules where you use it". This will keep you out of trouble when it comes to having or not having the definitions around.

眼眸 2024-10-11 07:29:27

我通常不会使用 pragma Once 因为 pragma 不是标准的。您可能必须将代码移植到未定义的不同编译器,并且必须使用 #ifndef ... #define 习惯用法重写每个代码。

这是因为我直接使用 #ifndef ... #define

第二件事:在头文件中使用许多包含并不是一个好主意:我总是尝试最小化它们。如果它们太多,每次更改其中一个的一点点时,您都​​必须重新编译每个依赖的 .cpp 文件。

如果是这种情况,我采用 Pimpl 习惯用法,您可以在此处<找到描述。 /a> (参见 C++ 示例)。无论如何,如果项目规模不是那么大,我认为你的方法是正确的。

I usually don't use pragma once because pragmas are not standad. You could have to port your code to a different compiler where it's not defined, and you'd have to rewrite each with #ifndef ... #define idiom.

This is because I go straight with #ifndef ... #define.

Second thing: using many includes in an header file is not a good idea: I always try to minimize them. If you got too much of them, each time you change a little thing in one of them you'll have to recompile each dependent .cpp file.

If that's the case, I adopt the Pimpl idiom, that you can find described here (see the C++ example). Anyway, if the project's size is not that big, I think that your approach is correct.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文