这是一个相当基本的问题,但它是一个让我误解了一段时间的问题。
我的项目有一堆.cpp(实现)和.hpp(定义)文件。
我发现当我添加其他类和更多类的相互依赖时,我必须#include其他头文件。一两个星期之后,我最终在很多地方使用了#include指令。稍后,我会尝试删除一些#includes并发现一切仍然有效,因为其他包含的类也包括#include我刚删除的内容。
是否有一个简单易行的规则可以放入#includes来阻止这个丑陋的混乱发生在一开始?什么是最佳做法?
例如,我曾参与过一些项目,其中Implementation .cpp文件只包含相应的Definition .hpp文件,而没有别的。如果Implementation .cpp需要使用任何其他.hpp文件,则它们都由Definition .hpp文件引用。
答案 0 :(得分:18)
一些最佳做法:
每个标题都包含:
#ifndef HEADER_XXX_INCLUDED
#define HEADER_XXX_INCLUDED
...
#endif /* HEADER_XXX_INCLUDED */
标题不会在周期中包含彼此
这些不一定是“最佳实践”,但我通常遵循的规则也是:
#include "..."
之前和系统范围标头之前,其中包含#include <...>
答案 1 :(得分:10)
查看John Lakos的大规模C ++软件设计。这就是我所遵循的(作为例子写的):
// 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
答案 2 :(得分:7)
我总是使用最小耦合原理。如果当前文件实际需要,我只包含一个文件;如果我可以使用前向声明而不是完整定义,我将使用它。我的.cpp文件总是在顶部有一堆#includes。
Bar.h:
class Foo;
class Bar
{
Foo * m_foo;
};
Bar.cpp:
#include "Foo.h"
#include "Bar.h"
答案 3 :(得分:5)
仅使用所需的最少量包含。无用包括减慢编译速度。
此外,如果只需要指向类,则不必包含标题。在这种情况下,您可以使用前向声明,如:
class BogoFactory;
编辑:只是为了说清楚。当我说最低金额时,我并不是指建立包含链条的链接:
a.h
#include "b.h"
b.h
#include "c.h"
如果a.h需要c.h,当然需要将其包含在a.h中以防止出现维护问题。
答案 4 :(得分:3)
C / C ++中使用的#include模型存在一些问题,主要的一个问题是它没有表达实际的依赖图。相反,它只是按照特定的顺序连接一堆定义,通常导致每个源文件中的定义以不同的顺序排列。
通常,您需要知道软件的包含文件层次结构,就像您了解数据结构一样;你必须知道哪些文件包含在哪里。阅读您的源代码,了解哪些文件在层次结构中处于高位,这样您就可以避免意外添加包含,以便“从任何地方”包含它。添加新的包含时请认真思考:我是否真的需要在此处添加此内容? 我执行此操作时会提取哪些其他文件?
两个惯例(除了已经提到的那些)可以提供帮助:
答案 5 :(得分:2)
以antti.huima所说的为基础:
假设你有A,B和C类.A取决于(包括)B,A和B都依赖于C.有一天你发现你不再需要在A中包含C,因为B做到了为你,所以你删除了#include
声明。
现在如果将来更新B不再使用C,会发生什么?突然间,A没有任何理由被打破。
答案 6 :(得分:1)
在A.cpp中,首先要包括A.h,以确保A.h没有其他依赖项。 在所有系统文件之前包括所有项目文件之前的所有本地(相同模块)文件,再次确保不依赖于预先包含的系统文件。 尽可能使用前向声明。 使用#indef / #define / #endif pattern 如果A.h中包含标题,则无需将其包含在A.cpp中。必须明确包含A.cpp所需的任何其他标头,即使它们恰好由其他.h文件提供。
答案 7 :(得分:0)