C 和 C++ 区分声明和定义。
您可以多次声明一个符号,但您只能定义一次。通过学习这一点,我有一个想法,将声明放在守卫之外,而将定义放在守卫内部:
// declarations
int foo(int x, int y);
int bar(int x, int y);
extern double something;
class X;
#ifndef _MY_HEADER_H_
#define _MY_HEADER_H_
#include "otherheader1.h"
#include "otherheader2.h"
// definitions of structures, classes.
class X
{
// blah blah...
};
#endif
通过这种方式,我可以包含我想要的任何顺序的标题。并且可能循环依赖不会成为问题。
那么,如果我们可以将声明放在外面,为什么还要用保护令牌来保护整个标头呢?
我的理由如下:
当两个标题以某种方式相互引用时,您可能经常遇到问题。您通常会收到未声明的符号错误,您的第一反应是包含必要的标头。但是,当您的两个标头碰巧相互包含时,您会得到一些神秘的错误。
啊:
#ifndef A_H
#define A_H
#include "b.h"
class A {B *b;}
#endif
bh
#ifndef B_H
#define B_H
#include "a.h"
class B {A *a;}
#endif
当在 b.cpp 中包含 bh 时,您会在 ah 中得到一个错误,即 B 未声明但包含标头。(这是一个wtf时刻。)
这是因为头卫不会嵌套:
#ifndef B_H
#define B_H
#ifndef A_H
#define A_H
// B_H already defined no include here.
class A {B *b;}
#endif
class B {A *a;}
#endif
如果您将声明放在守卫之外,则可以防止这种情况:
class B; // in b.h
#ifndef B_H
#define B_H
class A; // in a.h
#ifndef A_H
#define A_H
class B; // again from b.h
// B_H already defined no include here, no redefinition.
class A {B *b;}
#endif
class B {A *a;}
#endif
这里没问题。
更新:将标头包含在警卫中(对不起,这是一个错误)。