Accessing data of including class

Ok, so here's my basic situation: I'm writing a game, and I have one class, Game, that stores the majority of the game data. This includes a vector of another class, Player. But in the Player class, I need to access data from the Game class. Is there any easy way to do this without passing a bunch of pointers from my main class? The ideal would be to store a pointer to the Game class within the Player class, but of course that requires #including Game.h from Player and #including Player.h from Game which seems to cause all kinds of problems. So, anyone have any other suggestions?
One option is to make a static member of the Game class which retrieves the main Game object. This pretty much limits you to only 1 Game per program instance though, since your game object effectively becomes global.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// in your header
class Game
{
//...
  static void BeginGame()
  {
    theGame = new Game;
    theGame->Entry();  // Entry is a non-static entry point for the game
    delete theGame
  }
  static Game& get()
  {
    return *theGame;
  }
  static Game* theGame;
//...
};

/////////////////////
// in one cpp file only
Game* Game::theGame;

/////////////////////
//  whenever your Player class needs to access a Game member
void Player::somefunc()
{
  Game::get().SomeGameMember();
}

/////////////////////
//  your main entry point
int main() // or whatever entry point funciton you have
{
  Game::BeginGame();
  return 0;
}

Hmm. I like the idea, and it should work as I do only need one copy of the Game object, but I can't quite get it working. I think the problem is that I'm not actually running the game from the game class, I'm just using it to store data and perform some functions on them. But the point is, I need an instantiated copy of Game I can access from my main class. So what I'm trying to do is this:

in main():
1
2
Game::BeginGame(numPlayers);
Game* thisGame = Game::theGame; //throws error: 'undefined reference to 'Game::theGame'' 


in Game:
1
2
3
4
5
6
7
8
9
10
11
static Game* theGame;

	static void BeginGame(int np)
	{
		theGame = new Game(np);
	}

	static Game& get()
	{
		return *theGame;
	}


I did attempt replacing every instance of 'thisGame' with a direct call to Game::theGame, but that failed as well. Any thoughts?
Is this a linker error?

static members need to be declared once (globally) in a source file in order to be instantiated. You might have forgotten this bit:

1
2
3
4
/////////////////////////////////
//  put this in one and only one .cpp file
//   that is part of your project
Game* Game::theGame;


Without that line you're saying "this variable exists somewhere", but aren't actually creating it. That's why the linker barks at you.

Also -- just to doublecheck..... If you're making theGame with new, be sure you delete it somewhere.
Ok, I got it now. But I still can't use it in my Player class - It's saying ''Game' has not been declared'
Well if you're using 'Game' in a source file, you need to #include the header that declares it, of course.
Yea, I've done that. I think it may have something to do with the fact that Game includes Player and Player includes Game...
You can make a forward declaration. Rather than type a lengthy explanation here I'll link you to this page which describes it well. Just replace Fred/Barney with Player/Game:

http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.11

specifically sections 39.11, 39.12, and 39.13 are relevent
Ok, well that makes sense - basically the same thing you do with functions - but it still won't work. Because I don't want to just declare a pointer to some object. I need to actually access data members of that object, which forward declarations don't allow.

Edit:
Actually, I think I see what I need to do. I think I should be moving these Player functions into the Game class. Before I was thinking I would have to move them into my Main file, which would make things really ugly, or pass huge amounts of data between the main class and the player class, which would be even uglier, but I really should be putting these functions in the Game class and just passing the Player into that. I mean, if there is some way to do what I was asking, please let me know, as that would be slightly easier, but I think I know what I need to be doing.
Last edited on
You can do anything with forward declarations except have Player have a Game object and vice versa (which would create an infinite loop anyway if it were allowed -- Player.Game.Player.Game.etc)

- If Game has Player objects, then Player must be defined (ie: has a body) first
- If Game has Player pointers, then Player can be defined first, or you can forward declare Player prior to defining Game
and vice versa:
- If Player has Game objects, then Game must be defined first
- If Player has Game pointers, then Game can be defined first, or you can forward declare Game

If you're dealing with pointers only (no objects), then it doesn't matter which is defined first as long as you forward declare.

Assuming Game has Player objects, and Player only has a Game pointer, lay it out like so:

-) seperate them so Game is in "game.h" and "game.cpp", and Player is in "player.h" and "player.cpp"
-) guard against recursive/redundant includes with #ifndef and #define (I recommend doing this with all your headers)
-) in "player.h", forward declare Game, then define Player:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef __PLAYER_H_INCLUDED__
#define __PLAYER_H_INCLUDED__

// included dependencies for Player
   // if Player needs any objects *defined* before it, #include them here
   // do not include things you can forward declare

// forward declared dependencies for Player
class Game;
  // and anything else Player needs


// the actual Player class
class Player
{
 // stuff
  Game* game;  // okay!  Game is forward declared
};
#endif 

-) Since Game is forward declared in "player.h" -- do not inline anything that requires Game to be defined. Anything that actually uses Game will have to be put in "player.cpp" -- where both Game and Player will be fully defined with the right includes:
1
2
3
4
5
// in player.cpp
#include "player.h"  // defines Player, forward declares Game
#include "game.h"  // defines Game

// Player and Game now fully defined -- use at will 


-) alternatively to the above, you can #include "game.h" after the Player class is defined in "player.h" so that you don't have to #include it in "player.cpp". However I don't recommend that approach. In fact I probably shouldn't have even mentioned it XD

-) in "game.h", #include "player.h" since Player's full definition is required to exist before Game's definition exists. If player.h is guarded with #ifndef (as in the above example) there are no ill effects to putting the #include in the header. In fact, IMO, it makes the code much more managable because you know exactly what dependencies are needed where (no need to include 5 seperate files if you make a new source file that needs Game -- you can just include "game.h" and be done with it):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef __GAME_H_INCLUDED__
#define __GAME_H_INCLUDED__

// included dependencies for Game:
#include "player.h"   // Game needs Player defined

// forward declared dependencies for Game:
  // put other stuff you can forward declare here

class Game
{
  // stuff
  Player thePlayer;  // okay!  Player is fully defined
};
#endif 


As to whether or not it's the best design decision to have Player and Game communicate back and forth like this -- that's another topic =P. But this should work just fine if that's how you want to go.


EDIT-- forgot an #endif

Also -- what I suspect might be your problem is you're inlining function bodies in the class definition. This is fine as long as objects you use are fully defined. Since Player does not have Game fully defined... you can't inline functions in the class which use Game.

To elaborate further:

1
2
3
4
5
6
7
8
9
10
11
12
// in player.h
class Player
{
public:
  void SomeFunction()
  {
    game->DoSomething(); // Error!  game not fully defined.  Can't inline this function
  }

protected:
  Game* game;
};


Do this instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// in player.h
class Player
{
public:
  void SomeFunction();

protected:
  Game* game;
};

//-----------------------------------
//-----------------------------------
// in player.cpp

#include "player.h"
#include "game.h"

void Player::SomeFunction()
{
  game->DoSomething();  // okay!  Game is fully defined
}



* disclaimer. I'm using the term "inline" here as 'implicitly inlining' (ie: defining the function in the class itself). It is still possible to inline functions which use not-yet-fully-defined classes, but that's another topic.
Last edited on
Yea, as stated in my original post, Game contains a vector of Player objects, and I wanted to pass a Game object to a Player object. I suppose I could have changed the vector of Player objects to a vector of Player pointers, but that would have required changing a lot more code than just moving a few functions from Player to Game. Plus, when I really thought about it, the functions (things like a function that executes a player's turn) really belong in the Game class anyway.
closed account (z8vRko23)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>
using namespace std;

class  Bilhete{
 	string espectaculo;
 	int fila;
 	int lugar;
 public:
 	Bilhete(string espect, int fil, int lug);

	string getEspectaculo() const;
	bool filaPar(int fila) const;

};

Bilhete::Bilhete(string espect, int fil, int lug) {

 	espectaculo = espect;
 	fila = fil;
 	lugar = lug;
}

string Bilhete::getEspectaculo() const {

	return (espectaculo);
}

bool Bilhete::filaPar(int fila) const {

     return ((fila % 2) == 0);
}
Last edited on
closed account (z8vRko23)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <string>
#include <sstream>	
#include <fstream>
using namespace std;

#define FICH "alunos.txt"

class Aluno
{
	const string nome;
	string curso;
	int numero;
	int media;
public:
	Aluno(string umNome, string umCurso, int umNumero) : nome(umNome)
		{ curso = umCurso; numero = umNumero; media = 0; };
	string getNome() const	{ return nome; };
	string getCurso() const	{ return curso; };
	int getNumero() const	{ return numero; };
	int getMedia() const	{ return media; };
	void setDados(string umCurso, int umNumero, int umaMedia)
		{ curso = umCurso; numero = umNumero;  media = umaMedia; };
	void setDados(string umCurso, int umNumero)
		{ curso = umCurso; numero = umNumero; media = 0; };
	void setDados(int umaMedia)
		{ media = umaMedia; };
	string sigla();
      	void imprimirAluno(ostream &os);
};

string Aluno::sigla()
{
	string sigla, palavra;
	stringstream ss (nome);
while (ss >> palavra)
	sigla = sigla + palavra.at(0);
return sigla;
};

void Aluno::imprimirAluno(ostream &os)
{
os <<"\t"<< nome <<" | "<< curso <<" | "<< numero <<" | "<< media << endl;
}


int main()
{
ofstream file;
Aluno a2("Carlos Carvalho", "Ciclismo", 125);

cout << "Lista de alunos: (nome | curso | numero | media)" << endl;
a2.imprimirAluno(cout);
cout << endl;

file.open(FICH);
if (file)
	a2.imprimirAluno(file);
else
	{
	cerr << "\nErro na abertura do fich " << FICH << endl;
	return 1;
	}
file.close();

return 0;
}
Last edited on
Topic archived. No new replies allowed.