Reputation: 1288
Creating header guards for my h/hpp files has always been standard practice for me, but I wonder, why is it even possible to include de same file twice? Is there a case where you actually need unprotected headers?
Upvotes: 10
Views: 1705
Reputation: 72
Imagine you are writing your own template array wrapper (elements are pointers) for your tiny engine where array can either be:
so with this you can either create one class where all this handled but it would always check for what we can or cannot do. best is to create separate classes but here we have so much same code between them you could (if not careful) either make a mistake in one of them functions plus adding a new function would be slower.
so best is to take use of the "Parameterized" header files (as AnT stated) and simply create classes like
code example:
// TestDfM.h
#ifndef TEST_DFM_H
# define TEST_DFM_H
// first we need to make sure neither of these is defined
# ifdef Df_ARG1
# undef Df_ARG1
# endif
# ifdef Cl_First
# undef Cl_First
# endif
# ifdef Cl_Second
# undef Cl_Second
# endif
# ifdef Df_FIRST
# undef Df_FIRST
# endif
# ifdef Df_SECOND
# undef Df_SECOND
# endif
# ifdef TEST_DF_H
# undef TEST_DF_H
# endif
// we need this
# define Df_FIRST 1
# define Df_SECOND 2
// first class creation
# define Df_CLASS Df_FIRST
# define Df_ARRAY Cl_First
# include "TestDf.h"
// cleanup (after 1st)
# undef Df_CLASS
# undef Df_ARRAY
// second class creation
# define Df_CLASS Df_SECOND
# define Df_ARRAY Cl_Second
# define Df_ARG1
# include "TestDf.h"
// cleanup (after 2st)
# undef Df_CLASS
# undef Df_ARRAY
# undef Df_ARG1
// so we theoretically cannot include TestDf.h anymore (anywhere)
# define TEST_DF_H
#endif // TEST_DFM_H
// TestDf.h
// nothing to do here if the main header for this was not included
// also we should only call this inside the main header
#if defined(TEST_DFM_H) && !defined(TEST_DF_H)
# include "../Includes.h"
class Df_ARRAY {
public:
int m_shared;
# ifndef Df_ARG1
Df_ARRAY(int in_shared=0) { m_shared= in_shared; }
void f_info() { printf("out: %d\n", m_shared); }
# else
int m_x;
Df_ARRAY(int in_shared=0, int in_x= 7) { m_shared= in_shared; m_x= in_x; }
void f_info() { printf("out: %d [also has %d]\n", m_shared, m_x); }
# endif
# if Df_CLASS == Df_FIRST
void f_class() { printf("1st\n"); }
# elif Df_CLASS == Df_SECOND
void f_class() { printf("2nd\n"); }
# endif
};
#endif // TEST_DFM_H
// Main.cpp
#include "Array/TestDfM.h"
int main(int argc, char** argv) {
Cl_First a(6);
Cl_Second b(2);
a.f_class(); // 1st
b.f_class(); // 2nd
a.f_info(); // out: 6
b.f_info(); // out: 2 [also has 7]
return 0; }
Upvotes: 2
Reputation: 320777
"Parameterized" header files can be used to simulate C++-ish-style templates in C. In such cases the header file will depend on a number of macros ("template parameters"). It will generate different code depending on the actual "value" of these macros.
So, the typical usage of such header would look as a sequence of "template parameter" macro definitions followed by the #include
directive, followed by another sequence of "template parameter" macro definitions followed by the same #include
, and so on.
https://stackoverflow.com/a/7186396/187690
When using this technique you will see header files without any include guards or header files with include guards that cover only a portion of the file.
Upvotes: 10
Reputation: 154045
Header files are just textually included whenever they are encountered. There isn't any real reason why they can't be included more than once. If headers are only used for declaration and no definitions (and no declarations of templates with default arguments) there isn't even anything problematic with including them more than once.
That said <cassert>
is the canonical example of including a file more than once: You can change the definition of NDEBUG
and get different behavior from the assert()
macro within one translation unit.
Now having something like include_once
which includes a file just once turns out to be not as trivial as people tend to think. Here is an example where it isn’t clear how often foo.h
should be included:
#include_once "foo.h"
#include_once "./foo.h"
#include_once "bar/foo.h"
Assuming include_once
includes each file just once, how often should foo.h
be included? All three files can easily refer to the same physical file but this may not readily be visible, e.g., because one is a link to another one. It seems best to give the control to the programmer how can control how often they end up being used.
Upvotes: 1
Reputation: 755064
In C:
#undef NDEBUG
#include <assert.h>
...code using active asserts...
#define NDEBUG
#include <assert.h>
...code using disabled asserts...
Rinse and repeat. The analogue in C++ uses the header <cassert>
instead.
So, sometimes there are reasons to include a header twice. Not often, but there are reasons to do so.
Upvotes: 7
Reputation: 258678
Cases like these are rare, and when they do exist, a re-design is better suited anyway. One I can think of is headers that amass declarations:
//functions.h
virtual void foo();
virtual void goo();
//classes.h
class A : public Base
{
#include "functions.h"
};
class B : public Base
{
#include "functions.h"
};
This wouldn't work if functions.h
had include guards, but then again, this is pretty awkward code...
Upvotes: 2