pragma once and circular includes

Sep 27, 2018 at 2:20am
I am used to using defines and #if directive to make sure that already included headers are not included again. On my rewrite of a C++ project I haven't worked on in a while, I am trying #pragma once. Old headers were surrounded by
#ifndef A_H
#define A_H
... rest of code...
#endif

I have two headers that define inline functions. Both header files require each other to pass references of the other class type:

A.h
1
2
3
4
5
#pragma once
#include "B.h"
class A {
inline void someFunc(const B& var) { /*do something simple with var*/ }
};

B.h
1
2
3
4
5
6
#pragma once
#include "A.h"

class B {
inline void someFunc(const A& var) { /*do something simple with var*/ }.
};


When compiling B, it says that A is not defined. Can I solve this problem using #pragma once while still having them stay as inline functions?
Last edited on Sep 27, 2018 at 2:29am
Sep 27, 2018 at 4:44am
The easy answer is to forward declare the object (only using the value as a reference or pointer inside the header), and define all your functions inside a cpp file, and include the forward declared class from the header in the cpp file.

The actual answer is to avoid disgusting inter dependencies which causes coupling. One way of solving this is by reading the Gang of Four and applying the structures where you need them, and using KISS (and avoiding forward declarations when you CAN).

Which I cannot help you with because your example doesn't describe any sort of practical code.
Sep 27, 2018 at 7:48am
That makes sense in most cases. Except the point is for each inline function to call a function in the other class. That is the whole reason I need for them to include each other. Unless there is a way to forward declare member functions.

Here is a better idea of what I need to do:

A.h
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
#include "B.h"

class A
{
public:
	A();
	~A();

	inline void foo(B* b) { b->bar(); }
	void bar();
};


B.h
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
#include "A.h"

class B
{
public:
	B();
	~B();

	inline void foo(A* a) { a->bar(); }
	void bar();
};
Last edited on Sep 27, 2018 at 7:49am
Sep 27, 2018 at 2:27pm
"forward declare member functions"? Yes:
1
2
3
4
5
6
7
8
class A
{
public:
	void foo(B* b);
	void bar();
};

void A::foo(B* b) { b->bar(); }

Inlines? I don't think so.

Do you claim that the circular trap was accepted with the #ifndef header guards?
Sep 27, 2018 at 3:42pm
You could also just merge the headers into one and define the inline functions of the first class under the 2nd class. But I think you are silly if you are forcing yourself to live with these limitations because of performance of "inline", poorly written code will be 1000 times more expensive than any micro optimization you do.

It would make more sense to solve this in terms of practical code and avoid interdependent code when you can, can you describe your scenario of an actual circular dependency in your real code base?

I also wonder if the two objects are equal to each other, so maybe you can make an abstract type which is used by both A and B but the important functions used are inside the abstract class, so now you only need to pass in the abstract type into the function, and this effectively adds in flexibility depending on what your code is.

This is not a code problem (it is possible you don't know your forward declarations well), but an architecture problem. You cant expect us to give meaningful advice with this little info when code architecture is a very situational problem that depends on the context.
Last edited on Sep 27, 2018 at 5:58pm
Sep 27, 2018 at 7:02pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class B; //because the function expects a pointer
class A
{
public:
	void foo(B* b); //declaration
	void bar();
};

//class B has all that it needs, nothing special to do
class B
{
public:
	inline void foo(A* a) { a->bar(); }
	void bar();
};

//now define the member function
inline void A::foo(B* b){
	b->bar();
}
as #include is simply copy-paste you may do
1
2
3
4
5
6
7
8
9
//A.hpp
#pragma once
class B;
class A{
//...
};

#include "B.hpp"
#include "A-imp.hpp" 

1
2
3
4
5
6
//B.hpp
#pragma once
#include "A.hpp"
class B{
//...
}
Sep 27, 2018 at 8:46pm
You cant be sure that A.hpp is included first, if you include B.hpp first the code wont work since b is already included and when you include B.hpp the second time in A.hpp it gets skipped so A-imp.hpp (or equivalently the definition of A::foo) fails with an incomplete type.

I know this could be fixed easily by doing the same thing A.hpp is doing in B.hpp, but when you think about it, you are doing the exact same thing that example #1 is doing, which is if you include A, you include B, if you include B, you include A, so you could just include one to include both. Which is bad design and doesn't really make sense.

Also if your include declarations are not at the very top of your files, you are probably doing something wrong in an unnecessary complex way, and you will confuse anyone trying to read your code.
Sep 28, 2018 at 3:43am
1
2
3
//B.hpp
#include "A.hpp"
#pragma once 
Sep 28, 2018 at 4:36pm
That doesn't work the way you think.

(but it would if you used ifndef style header guards)
Last edited on Sep 28, 2018 at 4:46pm
Topic archived. No new replies allowed.