Multiple classes need to include each other.

I'm trying to distill what I want to do into a simple example, because I tried to write up the whole thing a couple times and it wound up way too convoluted to follow. Say I have three classes, contained in three different files. Here's what I want it to do.

A.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef _H_A
#define _H_A

using namespace std;

#include "B.h"

class A {
	public:
	B bArray[3];
	int counter = 10000;
	void aFunction() {
		if (counter-- > 0) {
//Never do this more than ten thousand times for a single A.
			for (int i = 0; i < 3; i++) {
//I need this pointer to make it all the way to class C.
				bArray[i].bFunction(this);
			}
		}
	}
};

#endif 


B.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef _H_B
#define _H_B

using namespace std;

#include "A.h"
#include "C.h"

class B {
	public:
	C cArray[3];
	void bFunction(A *aPointer) {
//B only needs this pointer to A in order to pass it along to C.
		for (int i = 0; i < 3; i++) {
			cArray[i].cFunction(aPointer);
		}
	}
	
};

#endif 


C.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef _H_C
#define _H_C

using namespace std;

#include "A.h"

class C {
	public:
	void cFunction(A *aPointer) {
		aPointer->aFunction();
//Since the same A that contains the B that contains this C is
//the one getting this function call, its counter will decrement
//and the recursion should be finite.
	}
	
};

#endif 


I know this won't work, and I know it has something to do with proper forward declarations. I've googled around and seen lots of different answers to questions that are very similar but not quite the same. None that I have tried have worked, but it's entirely possible that I'm overlooking something. Can anyone tell me the right way to structure this?
C.h
1
2
3
4
5
6
7
8
9
10
#ifndef _H_C
#define _H_C
// forward declare
class A;

class C {
public:
  void cFunction( A *aPointer );
};
#endif 

Size of A is not needed when defining C. It is enough to know that "A" is a class, because pointers are pointers.

C.cpp
1
2
3
4
5
6
#include "A.h"

void C::cFunction( A *aPointer )
{
  aPointer->aFunction();
}

The function has to know whether A has member aFunction(). B.h does not include C.cpp, so no circular includes.


B.h should cope with mere class A; too.
Last edited on
Unfortunately that doesn't seem to work for calling on members of A. Am I doing this right?
A.h is the same as before.
B.h no longer has #include A.h at the beginning, but instead has the forward declaration "class A;"
C.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef _H_C
#define _H_C

using namespace std;

class A;

class C {
	public:
	void cFunction(A *aPointer);
	C(){}
};

#endif   


C.cpp:
1
2
3
4
5
6
7
#include "C.h"

using namespace std;

void C::cFunction(A *aPointer) {
	aPointer->aFunction();
}


When compiling, it says:
1
2
3
4
5
6
7
8
g++ -g -c main.cpp
g++ -g -c A.cpp
g++ -g -c B.cpp
g++ -g -c C.cpp
C.cpp: In member function ‘void C::cFunction(A*)’:
C.cpp:6:10: error: invalid use of incomplete type ‘struct A’
C.h:6:7: error: forward declaration of ‘struct A’
make: *** [C.o] Error 1


EDIT: I've actually made a dummy project that's exactly like the question I'm asking here just to experiment with different ways of doing this, but the implementation I'm using here isn't totally like the implementation I'm using in my real code; for example, there's actually another step between A and C, but since its job is pretty much the same as B in this scenario I just put them together. Furthermore this setup isn't strictly the type of implementation necessary and is in fact a little less efficient than optimal. I feel like I should explain what I'm actually doing here.

I'm writing a raytracer. For those of you who don't know, it's basically a way to convert data describing a 3D scene into a 2D image by finding the intersection between the objects in the scene and rays cast from a virtual camera through individual pixels of a virtual image plane. The files involved here are trace.cpp, Ray.h and Ray.cpp, Intersection.h/cpp, Scene.h/cpp, Shape.h/cpp, Shader.h/cpp, and ShaderNode.h/cpp.

trace.cpp is the file that actually gets run. First, it reads in the scene data and sets up the Scene object. Then it sets up the camera and the virtual image plane. Next, it enters a loop where it goes through each pixel on the image plane, constructs a Ray from the camera to that pixel, and calls the Scene's raytraceScene function with that ray. The color output from that function then gets assigned to the corresponding pixel of the image and the loop moves to the next pixel.

Ray is my Ray class, which has a vector for the start point and a vector for the direction. Vectors and the associated math come from a separate included Vector class.

Intersection is a class that includes data about the different kinds of collisions that can happen between a Shape and a Ray. It stores data like the index of the hit object, the the location of the hit, texture coordinates, and a few other parameters based on what kind of object it is.

Scene is the class that defines where things are located. It includes an array of Shapes. It also has a function raytraceScene. This function goes into a loop through each shape, finds which shape, if any, intersects the ray closest to the camera, assigns the imporant data about that to an Intersection object, and then calls the getColor function on that shape using that data.

Shape is the class that describes the actual volume of a 3D body: what shape it is and where that shape is located in space. The class has a Shader object and a getColor function. The getColor function fills in the missing data on the intersection object it got passed, then passes that and the ray on to the shader's getColor function.

Shader basically describes how color and light works on the shape. It contains a root ShaderNode and a function getColor, whose whole purpose is to pass the same ray and intersection data it has to that root ShaderNode's getColor function. It basically only exists to have constructor functions which assemble ShaderNodes into some common configurations if I don't feel like constructing a tree of them from scratch.

The ShaderNode class and all of its child classes each serve a specific function with regards to different ways I might choose to have colors and light interact on a shape. It has a virtual getColor class that all of the different types inherit, and they do things like calculate and assign shadows, or find specular highlight values. Many of hem also contain pointers to other ShaderNodes. For example, a ShadowNode stores a ShaderNode for the color where light hits the object and another ShaderNode for where it doesn't. It calculates how much light hits the object there and blends between the output of those two ShaderNodes' getColor functions accordingly. In the simplest case, those would be static colors, but I could plug in something else like the ReflectionNode to make it more reflective where the light hits the object.

So raytracer includes Scene, Scene includes Shape, Shape includes Shader, and Shader includes ShaderNode, because each of those objects contain instances of the objects that they're storing. All of them need access to Ray and Intersection too. The part where the trouble comes in is that the ShaderNodes also need access to the Scene's members and raytrace function. For example, a ShadowNode needs to know where all the lights and objects in the scene are to determine how illuminated the object is and whether or not the lights are being blocked by something else. Another example, the ReflectionNode, is more like the A B C example I described above, in that its getColor function returns the output of a recursive call to raytraceScene.

One way or another, ShaderNode needs access to that scene and all its members and functions. That's my end goal. It doesn't necessarily need to pass a Scene pointer through the entire chain of command each time the raytrace function is called, I'd actually be much happier if it just always had access to one static pointer. However, I have to find some way to let ShaderNodes' functions use Scene's members and functions in its own functions. I've experimented with passing the Scene pointer to the ShaderNodes' constructors, or including it with Ray or Intersection, but in all cases my compiler either doesn't like me using members of something that hasn't been included or doesn't like me using ShaderNodes period. I've been stuck on this same problem for over a week now; any help anyone can give would be greatly appreciated.
Last edited on
C.cpp has to include A.h too.
Awesome! I never tried that and it worked. Thanks!
Topic archived. No new replies allowed.