Frage

C and C++ distinguishes between declarations an definitions.

You can declare a symbol many times, but you are allowed to define it only once. By learning this I have an idea to put declarations outside the guards, while definitions inside the guards:

// 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

By this way I can include my headers whatever order I want. And probably circular dependencies won't be a problem.

So why to protect the entire header with guard tokens if we can put the declarations outside?

My rationale was the following:

You probably often run into issues when two headers refer to each other somehow. You usually get an undeclared symbol error, and your first reflex is to include the necessary headers. But when two of your headers happen to include each other, you get cryptic errors.

a.h:

#ifndef A_H
#define A_H

#include "b.h"

class A {B *b;}       

#endif

b.h

#ifndef B_H
#define B_H

#include "a.h"

class B {A *a;}       

#endif

When in b.cpp you include the b.h you get an error in a.h that B is not declared but the header is included. (It's a wtf moment.)

It's because that header guards won't nest:

#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

If you put declarations outside the guard, you can prevent this:

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

No problem here.

UPDATE: put header inclusion into the guards (Sorry it was a mistake).

War es hilfreich?

Lösung

You're missing half the story when you think only about "declarations". C++ also has a notion of "class definitions", which are a third, new type of animal -- it's both a definition (of the class) and a declaration (of the member functions).

Since classes may not be defined more than once (just like for any definition), you must not include a header file with class definitions more than once.

Now imagine you have some utility class Foo in foo.hpp, and you have two, independent modules a.hpp and b.hpp which both require Foo. Your main program must include a.hpp and b.hpp, but now you're attempting to include foo.hpp, and hence the class definition of Foo, twice.

Enter include guards.

Andere Tipps

Because it allows you to #include a header several times without being afraid of conflicts.

While it is not necessary if you have one level of nesting, it is indispensable if you have several (consider including h1, then including h2 which includes h1 because it needs it).

there is no need if it is strictly a header guard - the declaration is already visible if multiply included.

another reason against this is that declarations outside a strict header guard may disable compiler optimizations for multiply included headers (that is, it will open the header more times).

You system does not protect against cyclic inclusion. For example:

Header A:

#include "B.h"
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
// ...
#endif // A_H_INCLUDED

Header B:

#include "A.h"
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
// ...
#endif // B_H_INCLUDED

Source file:

#include "A.h" // includes B, which includes A, which includes B, ...

A simple answer would simply be compilation speed. Compilers, like GCC and probably others, can detect a full-file header guard and avoid reading and reprocessing those files when encountered multiple times. If you don't wrap your entire file in the header guards there's a very good chance you'll be forcing your compiler to reevaluate the header every time it is encountered.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top