Including headers inside a declaration / class definition

I know you can do something like:

def.h:

A(); int x; 

hijras

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

a.cpp

 A::A() { x = 0; } int main() { A a; return 0; } 

My questions are: why do you do this? Are there any advantages? I see how it would be useful if you had classes with the same members, but not with the same base, but is it worth the hassle? It's not very readable, is it? Also, how does the compiler relate to them? Does it just insert the contents of the header where it was included (like a macro)?

+6
source share
5 answers

The preprocessor (which runs the earliest), when it comes across include , almost literally copies the contents of this header and inserts it instead of the #include directive.

The advantages of using it, as you described, are several, the main one of which is that you do not need to duplicate the code.

However, in situations of 9999/10000, this is definitely not worth the hassle. If you have a typo somewhere in the header file, you will get strange errors in every file that uses it, and he did not quite understand what it was doing until you really open the file and read it.

Avoid this, if at all possible. I cannot think of a situation where this would be absolutely necessary; the same effect can be achieved with inheritance or composition most of the time without any side effects.

+1
source

I have never seen this inside a class and would recommend that you never do this if you want to understand the code the other day.

However, there is a case where I consider this technique acceptable, and it is then that you have a large table from which you need to create several constructions, such as an enumeration and an attribute table. Suppose there are two files:

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 in "foobars.tab" (it is special, so I recommend not to call it Nothing.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 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) ... 

Another option is to define a macro for the contents of a special include. If the table is short, the macro is easier to read, but if the file is long, a special file makes sense.

The last option is to make the table as a whole different from the format and generate code, but this is due to writing a special script to create it, and this is not so.

+3
source

In languages ​​like Ruby, this concept is called Mixin . Since we have multiple inheritance in C ++, we do not need this here.

+2
source

One of the methods I found is that if you want to automatically generate a huge number of lines in the definition of your class, it may be useful to include an automatically generated file like this.

0
source

These answers are all very old, but I found a reason to do this, which is not mentioned above. I write automatic tests that require access to private members and, therefore, the use of friendship declarations in many classes. Since friendship is not inherited, I must explicitly declare the friendship of any new test class in each class with which it interacts.

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

 friend class testOneFeature; friend class testAnotherFeature; 

etc., and in the tested classes I can just include this file in the declaration.

 class MyClass { #include "test_friends.h" public: //etc }; 
0
source

Source: https://habr.com/ru/post/896869/


All Articles