C++头文件
如果我有A.cpp和A.h,以及b.h、c.h、d.h,那么我应该怎么做:
在A.h中:
#include "b.h"
#include "c.h"
#include "d.h"
in A.cpp:
#include "A.h"
或者
在A.cpp文件中:
#include "A.h"
#include "b.h"
#include "c.h"
#include "d.h"
有性能问题吗?明显的好处?这方面有什么不好的东西吗?
为编译程序只需包含必要的内容;添加不必要的包含将会损害编译时间,特别是在大型项目中。
每个头文件应该能够独立编译 -- 也就是说,如果您有一个仅包括该头文件的源文件,那么它应该可以无错误地编译。头文件应该仅包含必要的内容。
尽可能使用前置声明。如果您正在使用一个类,但头文件只处理该类的对象指针/引用,则不需要包含该类的定义 -- 只需使用前置声明:
class SomeClass;
// Can now use pointers/references to SomeClass
// without needing the full definition
这里的关键做法是在每个foo.h文件周围放置一个类似于以下的守卫:
#ifndef _FOO_H
#define _FOO_H
...rest of the .h file...
#endif
这样可以防止多次包含,循环等相关问题。一旦确保每个包含文件都受到了保护,具体细节就不那么重要了。
我喜欢Adam表达的一个指导原则:确保如果一个源文件只包含a.h
,它不会因为a.h
假设其他文件已经被包含而不可避免地出现错误--例如,如果a.h
需要在之前包含b.h
,它可以并且应该直接包含b.h本身(如果b.h之前已经被包含了,则守卫将使其成为无操作)
反之,源文件应该包含它所需要的头文件(宏、声明等),而不是假设其他头文件会神奇地出现,因为它已经包含了一些头文件。
如果您正在使用类的值,那么您需要在某个.h
中包含所有令人讨厌的类的详细信息。但对于一些通过引用或指针使用的情况,只需要一个裸的class sic;
即可。例如,如果类a可以使用类b的指针(即成员class b * my_bp;
而不是成员class b * my_b;
),则包含文件之间的耦合可以变得更弱(减少大量重新编译)--例如,b.h
可能只有class b;
这么简单,而所有令人讨厌的细节都在b_impl.h
中,它只被真正需要它的头文件包含...
#ifndef A_H_
#define A_H_
#include "D.h"
class B; //forward declaration
class C; //forward declaration
class A
{
B *m_pb; //you can forward declare this one bacause it's a pointer and the compilier doesn't need to know the size of object B at this point in the code. include B.h in the cpp file.
C &m_rc; //you can also forware declare this one for the same reason, except it's a reference.
D m_d; //you cannot forward declare this one because the complier need to calc the size of object D.
};
#endif
A.h
包含b.h
,c.h
和d.h
。经验法则是:只在头文件中包含必要的代码。任何不立即需要的内容都应由A.cpp
包含。#include
引用,则更改其中任何一个将需要递归地重新构建所有包含更改的头文件的其他文件。因此,如果您决定触摸某个顶级头文件,则可能会重建代码的大部分。T
的头文件t.h
中需要它。
T
的成员变量(注意,这不包括声明指向T
的指针)。T
类型对象的成员。如果您的头文件仅:
T
对象的引用或指针。T
对象的函数。T
对象的引用或指针的成员变量。考虑这个类的声明;您真正需要包含哪些A
、B
和C
的头文件呢?
class MyClass
{
public:
MyClass( const A &a );
void set( const B &b );
void set( const B *b );
B getB();
C getC();
private:
B *m_b;
C m_c;
};
C
的头文件,因为它有成员变量m_c
。通常情况下,你可以通过不直接声明成员变量,而是使用不透明指针将所有成员变量隐藏在私有结构中来消除这个要求,这样它们就不会再出现在头文件中了。最好不要在其他头文件中包含头文件 - 这会减慢编译速度并导致循环引用。
不会有性能问题,所有操作都在编译时完成,您的标题应该设置好,以确保它们不会被包含多次。
我不知道是否有标准的方法来做这件事,但我更喜欢在源文件中包含所有需要的头文件,并在头文件中包含它们,如果头文件本身需要它(例如,从另一个头文件中的 typedef)
SomeClass
,你也可以使用前向声明。 - Frerich Raabe