C++ 什么时候不需要包含?
我承认我有点天真,当涉及到包括。我的理解是,如果您在类中使用它,您需要包含它或向前声明它。但后来我通过一些代码看到了:C++ 什么时候不需要包含?,c++,include,C++,Include,我承认我有点天真,当涉及到包括。我的理解是,如果您在类中使用它,您需要包含它或向前声明它。但后来我通过一些代码看到了: // 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; // ... 有人能给我解释一下
// 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吗?此外,以这种方式组织有哪些优点/缺点?(除了明显的少打字之外。)
谢谢 把#include想象成将另一个文件的文本包含在这一个文件中——它与您在其中复制的文本完全相同。因此,在本例中,B和C不需要包含Helper的原因是因为您将它包含在同一个“编译单元”中,这就是.cpp文件及其所有包含项的组合所调用的。当您将某个头文件(或其他)包含到.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++中看到这一点,它只显示预处理的文件
在您当前的问题上下文中,您必须在B.h
和C.h
之前/之前包含helper.h
,并声明这些类型的对象
此外,依靠头文件的排列来让代码正常工作也不是一个好的做法,因为一旦稍微改变排列方式,整个层次结构就会崩溃,并出现几个编译错误
相反,如果您正在使用文件,请在文件中包含所有内容,并且可以使用#ifndef
防护装置来避免多次包含:
//helper.h
#ifndef HELPER_H
#define HELPER_H
// content of helper file
#endif
如果B
和C
的类定义实际上没有引用Helper
类的任何成员,那么编译器不需要在其头文件中查看Helper
类的完整定义。Helper
类的转发声明就足够了
例如,如果B
类的定义仅使用指向Helper
的指针或引用,则建议使用正向引用:
class Helper;
class B {
// <SNIP>
Helper* helper;
// <SNIP>
void help(const Helper& helper);
// <SNIP>
};
何时使用include和forward声明的规则相对简单:在可以的时候使用forward声明,在必须的时候使用include
这样做的好处很明显:包含越少,头文件之间的依赖关系就越少(编译速度就越快)。对于模板,即使头文件中引用了前向声明类型的成员,前向声明也可能足够了
例如,boost::shared\u ptr
实现仅向前声明boost::weak\u ptr
,即使它在两个构造函数中使用。以下是从中截取的代码:
namespace boost
{
// ...
模板类弱ptr;
// ...
模板类共享\u ptr
{
// ...
公众:
// ...
模板
显式共享\u ptr(弱\u ptr const&r):pn(r.pn)//可能抛出
{
//现在可以安全地复制r.px,因为pn(r.pn)没有抛出
px=r.px;
}
模板
共享_ptr(弱_ptr const&r,boost::detail::sp_nothrow_标记):px(0),pn(r.pn,boost::detail::sp_nothrow_标记())//从不抛出
{
如果(!pn.empty())
{
px=r.px;
}
}
在这种情况下,向前声明boost::weak_ptr
就足够了,因为除非向前声明的boost::weak_ptr
的定义包含在使用这些构造函数的编译单元中,否则这两个构造函数不会被实例化。这是错误的,您从哪里看到的?如果这些确实是在您显示给我们的文件的顶部,那么至少B.h需要包含定义Helper的文件,该文件可能是Helper,也可能不是Helper。h@Benjamin林德利,谢谢。你说得对,助手。h在B.h和C.h之前就已经包括在内了。它们不需要只是在同一个翻译单元中,它们需要顺序正确。在这种情况下,它们实际上是n谢谢你的回答。你对这种做法的警告是很好的。这就是我第一次发现的原因:我做了一个改变,然后得到了一长串编译错误。
#include "helper.h"
class B {
// <SNIP>
Helper helper;
// <SNIP>
void help(Helper helper);
// <SNIP>
};
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;
}
}