我承认,在涉及到包括时,我有点天真。我的理解是,如果你在课堂上使用它,你需要包含它或者向前声明它。但后来我经历了一些代码,我看到了这个:
// file: A.cpp
#include "Helper.h"
#include "B.h"
#include "C.h"
#include "A.h"
// ...
// file: A.h
B b;
C c;
// ...
// file: B.h
Helper h;
// ...
// file: C.h
Helper h;
// ...
有人可以向我解释为什么B和C不需要包含Helper吗?此外,组织的优点/缺点包括这种方式? (除了显而易见的打字之外。)
感谢。
答案 0 :(得分:5)
当#include
某个标头(或其他)文件放入.cpp
文件时,#include
语句只会被头文件的内容替换。例如:
//header.h
int i;
float f;
// file.cpp
#include"header.h"
int main()
{}
在预处理阶段之后,file.cpp看起来像,
int i;
float f;
int main()
{}
可以使用g++ -E file.cpp > TEMP
在g ++中看到这一点,它只显示预处理的文件。
在您目前的问题环境中,您必须在#include
之前/之前helper.h
B.h
和之前出现的C.h
并声明这些类型的对象。< / p>
此外,依靠头文件的排列来使代码工作是不好的做法,因为一旦你改变排列很少,整个层次结构就会崩溃并出现几个编译错误。
如果你正在使用它,那么#include
文件中的所有内容,你可以使用#ifndef
警卫来避免多次包含:
//helper.h
#ifndef HELPER_H
#define HELPER_H
// content of helper file
#endif
答案 1 :(得分:2)
如果B
和C
的类定义实际上没有引用Helper
类的任何成员,那么编译器不需要查看完整定义其头文件中的Helper
类。 <{1}}类的前向声明就足够了。
例如,如果Helper
类的定义仅使用指向B
的指针或引用,则建议使用转发参考:
Helper
如果class Helper;
class B {
// <SNIP>
Helper* helper;
// <SNIP>
void help(const Helper& helper);
// <SNIP>
};
类的定义使用B
类的实例(即,它需要知道Helper
实例的大小),或者以其他方式引用定义对于Helper
类(在模板函数中),那么你需要使Helper
类的完整定义可见(最有可能包括定义的头文件) Helper
类):
Helper
何时使用包括与前向声明的规则相对简单:尽可能使用前向声明,并且包括必须的时间。
这样做的好处很明显:你拥有的内容越少,头文件之间的依赖性就越少(你的编译速度就越快)。
答案 2 :(得分:1)
将#include视为字面上包含此文件中另一个文件的文本 - 它与您复制它的方式完全相同。所以在这种情况下,B和C不需要包含Helper的原因是因为你已经将它包含在同一个“编译单元”中,这就是调用.cpp文件及其所有包含的组合。
答案 3 :(得分:0)
使用模板,即使在头文件中引用了前向声明类型的成员,前向声明也可能就足够了。
例如,boost::shared_ptr<T>
实现仅向前声明boost::weak_ptr<T>
,即使它在两个构造函数中使用。以下是从http://www.boost.org/doc/libs/1_47_0/boost/smart_ptr/shared_ptr.hpp剪切的代码:
namespace boost
{
// ...
template<class T> class weak_ptr;
// ...
template<class T> class shared_ptr
{
// ...
public:
// ...
template<class Y>
explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw
{
// it is now safe to copy r.px, as pn(r.pn) did not throw
px = r.px;
}
template<class Y>
shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag ): px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) // never throws
{
if( !pn.empty() )
{
px = r.px;
}
}
在这种情况下,boost::weak_ptr<T>
的前向声明就足够了,因为除非前向声明boost::weak_ptr<T>
的定义已包含在使用这些构造函数的编译单元中,否则两个构造函数不会被实例化