Global objects, Classes with multiple objects, and recursive inclusion problem

So I'm having an issue that in PHP is solved very easily. I have taken C++ classes so I am not so far off from understanding, but obviously there is a learning curve here.

What I am trying to do is create a program.
The program contains an object class we'll call it Program; the Program object is supposed to be globally accessible everywhere in order to neatly access all of the different components from the other objects.

So, I declare my global object as

Program program;

I then add properties inside of Program to instantiate other object components.

So, Program declares ...

1
2
3
public: Graphics graphics;
public: Sound sound;
public: SomeItem item;


Now, the problem here is that in order to do this I must include all of these classes in the header for Program.

Now, when Graphics or SomeItem want to communicate with each other, I want them to access the global 'program' object. But in order to access it, I must recursively include the Program cpp file in each of the components (Graphics, Sound, SomeItem). But, Program includes Graphics, Sound, and SomeItem, making it recursive inclusion.

I'd like to, in SomeItem, be able to access properties of Graphics. So, I would like to be able to call program.graphics.example() from SomeItem. However, in order to access program, I have to include Program inside of SomeItem. Again, this makes it recursive.

Please help.
Last edited on
Avoiding globals, mantaining a reference to the program you are part of
1
2
3
4
5
6
7
8
9
//Sound.h
#pragma once
class Program; //there is a class called Program
class Sound{
//here only declarations
   Sound(/*...*/, Program &); //constructor
private:
   Program &program; //a reference to be able to access it
};

1
2
3
4
5
6
7
8
9
10
11
12
13
//Program.h
#pragma once
#include "Sound.h"
#include "Graphics.h"
#include "SomeItem.h"
class Program{ //the definition of the class
   //here only declarations
   public:
      Program(); //constructor
      Graphics graphics;
      Sound sound;
      SomeItem item;
};
1
2
3
4
5
6
7
8
9
10
//Program.cpp
#include "Program.h
//definition of the member functions
Program::Program():
//NOTE: in the items constructors you are only allowed to bind the reference,
//do not call any member function of Program
   graphics(/*...*/, *this), //passing yourself
   sound(/*...*/, *this), 
   item(/*...*/, *this)
{}
1
2
3
4
5
6
7
8
9
//Sound.cpp
#include "Sound.h"
#include "Program.h"
//definition of the member functions
Sound::Sound(/*...*/, Program &p):
   program(p) //getting the reference
{
	//...
}
1
2
3
4
5
6
7
8
//client code, main.cpp
#include "Program.h" //do not include *.cpp

int main(){
   Program foo;
   foo.graphics.example();
   Program bar; //can have another if you want
}


building
$ g++ -c {Program,Sound,Graphics,SomeItem,main}.cpp
$ g++ {Program,Sound,Graphics,SomeItem,main}.o -o program.bin

Last edited on
with a global `program' object
1
2
3
4
5
6
7
//Sound.h
#pragma once
class Program;
class Sound{
	//only declarations
	//do not need the reference or custom constructor
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Program.h
//almost the same as before
#pragma once
#include "Sound.h"
#include "Graphics.h"
#include "SomeItem.h"
class Program{ //the definition of the class
   //here only declarations
   public:
      Program(); //constructor
      Graphics graphics;
      Sound sound;
      SomeItem item;
};

extern Program program; //there is a global called `program' 

1
2
3
4
//Sound.cpp
#include "Sound.h"
#include "Program.h"
//member function definitions 
1
2
3
4
5
//Program.cpp
#include "Program.h"
Program program; //creating the global variable

//member functions definitions 
1
2
3
4
5
6
7
//client code, main.cpp
#include "Program.h"

int main(){
   //there is only one `program' object allowed
   program.graphics.example();
}

same building process


Also, check out Singleton
@ne555: your replies arrived while I was preparing mine (below). I'd be interested to know your thoughts on the relative merits of our two approaches. Thanks

OP: here goes ...

Without seeing any of your code I am guessing the relationships you have in mind is that Program has Graphics, has Sound, has SomeItem etc ... so just as public inheritance defines is-a relationships, private inheritance describes has-a relationships. Hence you can have each of these classes inherit privately from Program so that they can access Program's public and protected members.

Now if you also want SomeItem to be able to access properties of Graphics and so on then each of these classes become friends of each other. To do this you just need to forward declare the classes so that the compiler can see that these classes exist when it compiles and at run-time the full implementation of each class will be passed to the program. So your header file will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef HEADER_PROGRAM_H
#define HEADER_PROGRAM_H

class Program{//base class definitions; 
};

class Graphics;//derived class forward declarations;
class Sound;
class SomeItem;

class Graphics : private Program{//derived class definitions; 
    friend class Sound;
    friend class SomeItem;
};
class Sound : private Program{//similar to Graphics above;
};
class SomeItem : private Program{//similar to Graphics, Sound above;
};

endif
Thank you for your replies. The issue I am running directly into is that these methods simply do not appear to work in the way I am implementing them at least. Correct me if I am wrong.

I created Program; Program includes all the header files of of the components it is using. I take a component class & include the program.h file.

Even using #pragma once at the top of the component includes in Program, I am getting an error attempting to create a property from the class of a component that includes program.h.

So, if I place #include "program.h" inside of sound.h, suddenly program.h tells me Unknown type name 'Sound' as an error and I simply may not compile the program.

Is this a recursive problem? This is very frustrating to say that, but I will leave my emotions out.
The code I sent you had compiled fine on Code::Blocks but remember that is just the header (.h or .hpp) file. Now you need to #include this header file along with other necessary header files and namespaces in your implementation file (.cpp) and define, with appropriate scope resolution, all the methods used in the various classes in this implementation file. Then finally you'll have a third file (let's call it main.cpp) that actually has the main() function that runs the program.

Edit: needless to add, the three files mentioned above should be part of the same project
Last edited on
But in order to access it, I must recursively include the Program cpp file

You should never #include a .cpp file.
> I take a component class & include the program.h file.
> So, if I place #include "program.h" inside of sound.h, suddenly program.h
> tells me Unknown type name 'Sound'
Do not include `program.h' in `Sound.h'

Sound.cpp makes use of `program', so it must include `program.h'
Sound.h makes no use, a forward declaration would suffice.

Read this article, specially point 4 http://www.cplusplus.com/forum/articles/10627/
Also, include is simply copy-paste. You may try to make your program build from a single file, declarations at the top, definitions at the bottom, and after that builds correctly, separate them to .h and .cpp
1
2
3
4
5
class Program;
class Sound{/**/};
class Program{/**/};

//member functions 



@gunnerfunner: class Graphics : private Program, that means that `Graphics' has-a `Program', the relationship is backwards.
1
2
3
Graphics g;
Sound s;
Item i;
g, s and i have each one a `Program', a different `Program'. There is no relationship between g, s or i.

Hmm...
@OP: perhaps there is a bigger design issue. ¿what problem are you trying to solve?
you want the components to communicate between them, ¿what for?, ¿can't program manage all the communications?, ¿why do you need direct access to each component?
Yes, you're right. I was stretching the is-a analogy a bit too far in this instance. Your questions to OP are valid, without knowing too much about his/her aims, a general proposal might be to try having the classes as friends of each other but let's see what s/he comes back with ... thanks
Interesting ideas ...

So I made some progress, I think.

I created an umbrella header file; I included program.h in the umbrella.h file. I declared my global.

1
2
3
#pragma once
#include "program.h"
Program program;


I moved the #include program.h out of sound.h & into sound.cpp; it is much happier that way ... I am not sure if this is a longterm revelation, but for the time being it is a solution.

However, I am being thrown an error. These sorts of errors do not tell me what line they are on as far I know. They are complex, but I could ascertain from the cryptic message that it was from the sound.cpp file. It basically said "duplicate symbol _program in" ... to give you the gist.

So, including umbrella.h to include both program.h & the global reference to program has thrown a "duplicate symbol" error.
I suppose that it is a version of http://www.cplusplus.com/forum/general/140198/
In umbrella.h you need to write extern Program program;
Then in one and only one cpp Program program;

If the error persist, upload your project to github, it would be easier to recreate your file structure that way.
Yes!!! That fixed it! Thank you. I don't understand the logic, however. Will you explain it to me? Why must it be declared in a CPP file instead of an H file?

I'm sure I will be utilizing these forums in the future, so this is by no means the end :-)
antago wrote:
Why must it be declared in a [source] file instead of a [header] file?

Maybe your terminology is backwards: extern Program program; is the declaration, which (in this case) appears in a header file. Program program; is the corresponding definition, which must appear in exactly one translation unit* (source file).

If the instance is defined in the header file, then each translation unit gets its own instance with the same name (which is a violation of the ODR). You want to refer to the same program from every TU; this requires that the name program is declared with external linkage, as opposed to static linkage, which is the default for variables defined at global scope.

*Or no translation units at all, but only if the name program isn't ODR-used.
Last edited on
Topic archived. No new replies allowed.