6

I know you can do something like:

def.h:

A();
int x;

A.h

class A
{
public:
#include "def.h"
}

A.cpp

A::A()
{
    x = 0;
}

int main()
{
    A a;
    return 0;
}

My questions is: why would you do this? Are there any advantages? I can see how it would be helpful if you have some classes with the same members but not the same base, but is it worth the hassle? It's not very readable, is it? Also, how does the compiler treat these includes? Does it just paste the content of the header where it's included (kind of like a macro)?

Luchian Grigore
  • 236,802
  • 53
  • 428
  • 594

5 Answers5

3

I've never seen this inside a class and would recommend you to never do it if you want to still understand the code the other day.

That said, there is a case where I find this technique acceptable and that is when you have a large table from which you need to generate multiple constructs like an enum and an attribute table. Let's have two files like:

foobars.h:

enum Foobars {
#define FOOBAR(id, description, args) FOOBAR_##id,
#include "foobars.tab"
#undef FOOBAR
};

extern const char *foobar_names[];
const char *parse_foobar(Foobars fb, const char *input);

foobars.cpp:

#include "foobars.h"
const char *foobar_names[] = {
#define FOOBAR(id, description, args) description,
#include "foobars.tab"
#undef FOOBAR
};

const char *parse_foobar(Foobars fb, const char *input) {
    switch(fb) {
#define INT get_int(&input)
#define FLOAT get_float(&input)
#define STRING get_string(&input)
#define FOOBAR(id, description, args) args
#include "foobars.tab"
#undef FOOBAR
    }
return input;

And the magic is in "foobars.tab" (it's special, so I recommend not calling this anything.h or anything.hpp or any other common suffix):

/* CAUTION! This file is included using C preprocessor in the middle of various structures
 * It must not contain anything except definitions of foobars in the FOOBAR macro and
 * comments. Don't forget NOT to write semicolons; some of the structures are
 * comma-separated and some semicolon-separated. FOOBAR will be defined appropriately before
 * including this file. */
FOOBAR(NULL, "Empty command, does nothing", {}) // NO semicolon!
// Also some preprocessors don't like empty arguments, so that's why {}.
// (void)0 is an alternative.
FOOBAR(FOO, "Foo bars and bazes", a = INT; b = STRING)
FOOBAR(BAR, "Bars, but does not baz", x = FLOAT)
...

The other option is defining a macro to content of the special include. If the table is short, the macro is easier to read, but if the file is long, the special file makes more sense.

The last option is to have the table in altogether different format and generate the code, but that involves writing some special script for building it and this does not.

Jan Hudec
  • 65,662
  • 12
  • 114
  • 158
  • _"I've never seen this inside a class"_ ... me neither. Until yesterday, when I had a look into a header of an external DLL that has got exactly this. I was looking for a function declaration that we call in our code but couldn't find it in the included header. Then I found this include inside the class and then I understood. Some really weird people out there... :x – Andreas Feb 02 '17 at 08:59
2

The preprocessor (which runs before anything), when it stumbles upon an include, almost literally copies the content of that header and pastes it in the place of the #include directive.

The advantages of using it like you describe are few, the main one being that you don't have to duplicate code.

However, in 9999/10000 situations, it is definitely not worth the hassle. If you have a typo somewhere in the header file, you'll get strange errors in every file that uses it, and it's not clear at all what it's doing until you actually open the file and read it.

Avoid that if at all possible. I can't think of a situation where it would be absolutely necessary; the same effect can be achieved with inheritance or composition most of the time without all the side-effects.

Seth Carnegie
  • 70,115
  • 19
  • 169
  • 239
2

In languages like Ruby this concept is known as Mixin. Since we have multiple inheritance in C++, we don't need it here.

alfa
  • 2,990
  • 3
  • 22
  • 35
  • Well, implementing a mixin with the preprocessor is a bit better than multiple inheritance, because it does make the client become a sub-type of the mixin type. The main issue with implementing mixins with includes is that C++ developers may find it confusing (because it is not an idiomatic technique). – Mankarse Sep 08 '11 at 11:20
  • 1
    @Mankarse What is the problem with becoming a sub-type of the mixin type? – R. Martinho Fernandes Sep 08 '11 at 11:30
  • 1
    @R. Martingo Fernandes - It means that you are stuck with the mixin. If you want to change your implementation at some later stage it could cause client code (such as `A a; mixin& b = a;`) to break. – Mankarse Sep 08 '11 at 11:34
  • And if you need to write that client code, it won't work with the preprocessor. I don't see a strict advantage. I see tradeoffs. – R. Martinho Fernandes Sep 08 '11 at 11:38
  • alfa -- if you use protected or private inheritance then it will be impossible (practically) for a client to use the functionality at all, so it defeats the purpose. @R. Martinho Fernandes - I was more talking about the case when that code gets written by accident because the compiler allows it, even though it is not really future-proof or correct. – Mankarse Sep 08 '11 at 11:44
  • @Mankarse: ok, that's a valid concern. And regarding non-public inheritance: you can bring the functionality into public scope with `using`, while making upcasts forbidden. Yes, this is ugly, just pointing out that it is not impossible for a client to use it. – R. Martinho Fernandes Sep 08 '11 at 11:47
  • @R. Marthinho Fernandes: You are right. But I think this won't often cause real problems in practice. – alfa Sep 08 '11 at 11:48
1

One usage I found is that if you want to automatically generate a huge number of lines in your class definition, it could be helpful to include the auto-generated file like this.

Derek
  • 965
  • 1
  • 17
  • 32
0

These answers are all very old but I have found a reason to do this that is not listed above. I am writing automated tests which require access to private members, and thus the use of friendship declarations in many classes. Since friendship is not inherited, I have to explicitly declare friendship of any new test class in every class that it interacts with.

This is much easier to do if there is one or more files listing my test classes as per "test_friends.h" :

friend class testOneFeature;
friend class testAnotherFeature;

etc and in the tested classes I can simply include that file in the declaration.

class MyClass
{
#include "test_friends.h"
public:
 //etc 
};
mike
  • 963
  • 6
  • 24