pragma once and circular includes

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
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.
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
"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?
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
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{
//...
}
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.
1
2
3
//B.hpp
#include "A.hpp"
#pragma once 
That doesn't work the way you think.

(but it would if you used ifndef style header guards)
Last edited on
Topic archived. No new replies allowed.