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

时间:2010-11-25 07:52:21

标签: c++ include methodology

作为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继承自Parent类,则必须将它包含在* .h和* .cpp文件中
  • 如果ClassA使用ClassB(并且在类的范围内声明了ClassB变量),则它在ClassA.h中具有class ClassB; decleration,在ClassA.cpp中具有#include "ClassB.h"
  • 如果ClassA使用StructC(并且在类的范围内声明了StructC变量),则必须将它包含在ClassA.h和ClassA.cpp中
  • 如果ClassA使用ClassD或StructE但只在ClassA.cpp文件中使用,那么它应该仅包含它们

这可能是一套笨拙的指导方针,对底层逻辑几乎一无所知,所以我可能会有一些愤怒......带上它,我 am 尝试在这里学习......:)

更新

  • 正如一些人在下面写的那样,我在示例中有一个错误 - 只有当ClassA有一个指针或对ClassB的引用时才可以在ClassA中使用ClassB的前向声明,而不是如果它有一个简单的ClassB数据成员。

5 个答案:

答案 0 :(得分:9)

这些是我个人遵循的指导原则:

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

关于其他方面:

  • #pragma不标准,更喜欢include guards
  • 请注意,您永远不应转发声明标准类型:如果您的标头文件中出现std::string,则 #include <string>
  • 如果您最终得到一个包含一百万个其他文件的头文件,您可能需要查看pimpl idiom以减少依赖项(本文还包含有关头文件的其他一些指导原则)。

答案 1 :(得分:1)

#pragma once是非标准的(但受到广泛支持),因此您可能/可能不想使用#ifdef警卫。

至于你是否需要#include任何特定标题,这取决于。如果代码只需要一个前向声明,那么通过向前声明类型来避免导入。

除了模板内容之外,我认为在头文件中放置长函数定义可能并不太好。

话虽如此,我认为ClassA.h实际上应该包含ClassB.h,因为ClassA.h的任何用户(可能使用ClassA)都必须ClassB.h }。好吧,如果它正在做分配它的任何事情。

答案 2 :(得分:1)

当Class具有此类型的数据成员时,不要使用Class的前向声明。 当它有一个指向B类的指针时,可以使用它,如:

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

答案 3 :(得分:0)

我从Python中获得的一件事(因为它是绝对的要求)是“在你使用它的模块中导入(包括)它”。这将使您在拥有或不具备定义时避免麻烦。

答案 4 :(得分:0)

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

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

第二件事:在头文件中使用多个包含不是一个好主意:我总是尽量减少它们。如果你有太多的东西,每次你改变其中一个小东西时,你将不得不重新编译每个依赖的.cpp文件。

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

相关问题