C++ 是否有C&x2B的标准“包含约定”+;?

C++ 是否有C&x2B的标准“包含约定”+;?,c++,include,C++,Include,这是一个相当基本的问题,但这个问题困扰了我一段时间 我的项目有一堆.cpp(实现)和.hpp(定义)文件 我发现,随着我添加更多的类和更多的类间依赖关系,我必须包含其他头文件。一两周后,我在很多地方都得到了“包含指令”。稍后,我将尝试删除一些#include,并发现所有内容仍然有效,因为其他一些包含的类也#包括我刚才删除的内容 是否有一个简单易行的规则来加入“包含”,从一开始就可以阻止这种糟糕的局面发生?最佳做法是什么 例如,我曾经从事过这样的项目:Implementation.cpp文件只包含

这是一个相当基本的问题,但这个问题困扰了我一段时间

我的项目有一堆.cpp(实现)和.hpp(定义)文件

我发现,随着我添加更多的类和更多的类间依赖关系,我必须包含其他头文件。一两周后,我在很多地方都得到了“包含指令”。稍后,我将尝试删除一些#include,并发现所有内容仍然有效,因为其他一些包含的类也#包括我刚才删除的内容

是否有一个简单易行的规则来加入“包含”,从一开始就可以阻止这种糟糕的局面发生?最佳做法是什么

例如,我曾经从事过这样的项目:Implementation.cpp文件只包含相应的Definition.hpp文件,而没有其他文件。如果有任何其他.hpp文件需要由Implementation.cpp使用,它们都会被Definition.hpp文件引用。

一些最佳做法:

  • 每个.cpp或.C文件都包含它需要的所有头文件,不依赖头文件,包括其他相关头文件
  • 每个.hpp或.h文件都包含其所有依赖项,不依赖包括其他相关头在内的包含头
  • 每个标题都用以下内容包装:

    #ifndef HEADER_XXX_INCLUDED
    #define HEADER_XXX_INCLUDED
    ...
    #endif /* HEADER_XXX_INCLUDED */
    
  • 标题在循环中不包含彼此

  • 通常情况下:只有一个“项目范围的头文件”,如“config.h”或“.h”,它总是首先包含在任何.cpp或.C文件中。通常,它具有与平台相关的配置数据、项目范围的常量和宏等
这些不一定是“最佳实践”,而是我通常遵循的规则:

  • 项目特定标题包括在系统范围标题之前,作为
    #include“…”
    ,作为
    #include
  • 特定于项目的标题按字母顺序包含,以确保不存在意外的隐藏要求。由于每个标头都应该包含其从属项,并且标头应该受到保护以防止多次包含,因此您应该能够按照您希望的任何顺序包含它们

仅使用所需的最低数量的内含物。无用的包含会降低编译速度

此外,如果只需要指向类的指针,则不必包含头。在这种情况下,您可以使用如下转发声明:

class BogoFactory;
编辑:只是为了弄清楚。当我说最低金额时,我并不是指建立包括以下连锁店的连锁店:

a.h
#include "b.h"

b.h
#include "c.h"

如果a.h需要c.h,它当然需要包含在a.h中,以防止维护问题。

我总是使用最小耦合的原则。我仅在当前文件实际需要时才包含该文件;如果我可以用一个转发声明而不是一个完整的定义,我会用它来代替。我的.cpp文件顶部总是有一堆#include

B.h:

class Foo;

class Bar
{
    Foo * m_foo;
};
Bar.cpp:

#include "Foo.h"
#include "Bar.h"

基于antti.huima所说的:

假设你有A、B和C类。A依赖于(包括)B,A和B都依赖于C。有一天你发现你不再需要在A中包括C,因为B是为你做的,所以你删除了那个
#include
语句


现在,如果在将来的某个时候,您更新B以不再使用C,会发生什么情况?突然间,a被破坏了,没有什么好的理由。

C/C++中使用的#include模型有几个问题,主要问题是它不能表示实际的依赖关系图。相反,它只是以特定的顺序连接一组定义,通常会导致定义在每个源文件中以不同的顺序出现

一般来说,软件的include文件层次结构是您需要知道的,与您了解数据结构的方式相同;您必须知道从何处包括哪些文件。阅读您的源代码,知道哪些文件在层次结构中处于较高的位置,这样您就可以避免意外地添加include,从而“从任何地方”将其包括在内。当你添加一个新的include时,仔细想想:我真的需要在这里包括它吗?当我这样做的时候,会在其中绘制哪些其他文件?

有两个公约(除了已经提到的公约外)可以提供帮助:

  • 一个类==一个源文件+一个头文件,名称一致。类A包含在A.cpp和A.h中。这里的代码模板和代码片段可以减少在单独文件中声明每个类所需的键入量
  • 使用Impl模式避免在头文件中公开内部成员。impl模式意味着将所有内部成员放在.cpp文件中定义的结构中,并且在类中只有一个带有前向声明的私有指针。这意味着头文件只需要包含其公共接口所需的头文件,而其内部成员所需的任何定义都将保留在头文件之外

在A.cpp中,始终首先包括A.h,以确保A.h没有其他依赖项。 在所有系统文件之前包含所有项目文件之前包含所有本地(同一模块)文件,再次确保任何内容都不依赖于预先包含的系统文件。 尽可能多地使用正向声明。 使用#indef/#define/#endif模式
如果a.h中包含标题,则不需要将其包含在a.cpp中。任何其他的头文件.Apple CPP的需求必须明确包含,即使它们恰好是由其他.H文件提供的。

< P> >查看John Lakos的大规模C++软件设计。以下是我所遵循的(作为示例编写):

接口
//foo.h
//1)标准包括防护装置。不要使用下划线作为前缀。
#ifndef项目_FOO_H
#定义项目_FOO_H
//2)包括编译所需的所有依赖项
#包括
//3)更喜欢远期申报,而不是#包括
分类栏;
Baz类;
#include//STL方法向前声明istream,ostream
类Foo{…};
#恩迪夫
// foo.h
// 1) standard include guards.  DO NOT prefix with underscores.
#ifndef PROJECT_FOO_H
#define PROJECT_FOO_H

// 2) include all dependencies necessary for compilation
#include <vector>

// 3) prefer forward declaration to #include
class Bar;
class Baz;
#include <iosfwd> // this STL way to forward-declare istream, ostream

class Foo { ... };
#endif
// foo.cxx
// 1) precompiled header, if your build environment supports it
#include "stdafx.h"

// 2) always include your own header file first
#include "foo.h"

// 3) include other project-local dependencies
#include "bar.h"
#include "baz.h"

// 4) include third-party dependencies
#include <mysql.h>
#include <dlfcn.h>
#include <boost/lexical_cast.hpp>
#include <iostream>
// stdafx.h
// 1) make this easy to disable, for testing
#ifdef USE_PCH

// 2) include all third-party dendencies.  Do not reference any project-local headers.
#include <mysql.h>
#include <dlfcn.h>
#include <boost/lexical_cast.hpp>
#include <iosfwd>
#include <iostream>
#include <vector>
#endif