Struggling with classes and how to access them properly...

Started by
10 comments, last by Estauns 22 years, 2 months ago
Hey all, I'm having some problems trying to access an instance of a class. Rather then try to fill you in, I'm just going to post my code and show you. (Its short and for a console window, since I'm not implementing it into any sort of game anytime soon.... not with these "r337" C++ skills.. lol): Heres the basic run-down. I have a class declared in one file, I make an instance of that class in another file and then I want to access it in another file. The problem that arises, is this: c:\programming\c++\console apps\combat\main.cpp(12) : error C2065: 'world' : undeclared identifier c:\programming\c++\console apps\combat\main.cpp(12) : error C2228: left of '.terrainDisplay' must have class/struct/union type So here goes.. First, this is the decleration of my Terrain and its functions... terrain.h
  
// CTerrain handles all land features, from drawing it to creating it.

class CTerrain
{
public:
	CTerrain();
	~CTerrain();
	void terrainGenerate(void);
	void terrainDisplay(void);
	int iHeightMap[640];
};
  
terrain.cpp
  
#include "terrain.h"
#include "util.h"
#include <iostream.h>

CTerrain :: CTerrain()
{
	CTerrain :: terrainGenerate();
}

CTerrain :: ~CTerrain()
{

}

void CTerrain :: terrainGenerate(void)
{
	int iHeight = 240; // Middle of the terrain

	for(int iLoop = 0; iLoop <= 640; iLoop++)
	{
		iHeightMap[iLoop] = iLoop; // Do some random stuff here

	}
	return;
}

void CTerrain :: terrainDisplay(void)
{
	for(int iLoop = 0; iLoop <= 640; iLoop++)
	{
		cout << iHeightMap[iLoop];
	}
	return;
}
  
In init.cpp and init.h, I basically make an instance of the class. Right now its bland, but later on it will set up the number of players, etc. init.h
  
// Initilization

void InitGame(void);
  
init.cpp
  
// Initilization of all important game data

#include "init.h"
#include "terrain.h"

void InitGame(void)
{
	CTerrain world;
	return;
}
  
And now in main.cpp, this is where I want to access the world instance. main.cpp
  
// Combat War Sim... I guess =P


#include <iostream.h>
#include "terrain.h"
#include "util.h"
#include "init.h"

int main(void)
{
	InitGame();
	cout << "Blah!\n";
	world.terrainDisplay();
	return 0;
}
  
So any ideas why I get the erorr above, and what I can go about to fixing it? And maybe what would be the most memory effective method aswell? (Not as big a deal, though) Thanks guys. Edited by - Estauns on February 21, 2002 5:28:07 PM
"Where genius ends, madness begins."Estauns
Advertisement
You seem to be having trouble understanding scoping rules. In the function InitGame(), you do this:

  void InitGame(void){	  CTerrain world;	  return;}  


Which creates an auto variable called "world" of type CTerrain. What auto means is that the lifetime of the variable is automatically handled by the compiler, and it will be deleted at the end of the scope in which it is declared. That means "world" only exists until the end of the InitGame() function.

Then you do this:

  int main(void){	  InitGame();	  world.terrainDisplay();	}  


You''re clearly expecting world to exist here, so that you can call methods on it. However, the "world" that you created in InitGame() has been deleted, right? So, the compiler can''t see a variable called "world" at this point, and it can''t figure out what you are trying to tell it. You have several choices to fix this. Since InitGame() doesn''t really do anything, you could simply say:

  int main(void){	  CTerrain world;  world.terrainDisplay();	}  


And get rid of InitGame(). This is probably the best choice at the moment, as you should always try and keep objects local to where they are used.

However, in the future, you will find that you come up against problems which require you to invent more intricate solutions. It would be best if you didn''t worry about those problems now, else you won''t make any progress with your program. Instead, build the program up in small increments and make it do exactly what it needs to do. As you gain more practice you''ll find that you will be able to foresee impending problems and take action before you hit them. In the meantime, there''s only one way to gain the necessary practice...

--
The placement of a donkey''s eyes in its head enables it to see all four feet at all times.
Oh, and don''t worry about the "most memory effective method". You need to get your program working first. It doesn''t matter how memory efficient your program is if it doesn''t work. Only worry about memory when you know your program is taking up too much.

--
The placement of a donkey''s eyes in its head enables it to see all four feet at all times.
The problem is what''s called ''variable scoping''. A variable is accessable by name only if it is ''in scope''. Variables can be in one of a number of scopes:

Global - accessable throughout application.
Static - accessable inside the file they are declared in.
Local - accessable inside a procedure or block.

First problem: your ''world'' variable is declared local to the InitGame procedure, and thus can only be accessed from inside that procedure. You can move it out of the procedure, thus making it a global variable, as in:
  // Initilization of all important game data#include "init.h"#include "terrain.h"CTerrain world;void InitGame(void){    return;}[\source]Now, ''world'' is a global variable.  But, you also need to tell the compiler that it is a global variable when accessing it from another file.  You do that with:[source]extern CTerrain world;[\source]I''d suggest finding a good introductory C++ book and reading up on variable scoping.  A good introductory source is better than trial and error.  Good luck.  
Alright guys thanks, that makes perfect sense.

So would like "professional" games have global variables for its world and player structures? Or how would they work (I''ll stick to your suggestions for now, but I''m very curious about this).

Thanks again =)
"Where genius ends, madness begins."Estauns
I''ve actually been wondering the same thing, how do the "big boys" avoid a lot of global variables? Anyone know?
By passing them as function parameters, or having them as class members. It''s not hard when you think about it. Globals are the lazy answer.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]
The trouble with global variables is that it becomes all too easy to make various modules depend on that global variable, thus implicitly tying those modules together. This makes it difficult (or, even, impossible) to encapsulate these modules from change, as they are all affected by changes to the global variable, and changes to the way the variable is used by other modules. This becomes more problematic the larger your project becomes: the more global variables and dependent modules, the greater the chance of insidious bugs appearing from seemingly innocent changes.

The way around this is really to think carefully about where the "global" variable is actually needed, and consider alternate mechanisms for making the variable available to the modules which need it. For example, you might have an object that is needed by 3 other modules. Rather than make the object global, you might create the object on the heap, and register it with the 3 modules that have an interest in using it (i.e. store a pointer to the object). This then introduces the dilemma of who "owns" the object and, therefore, who should be responsible for deleting the object. Since the ownership policy is quite clearly one of shared ownership, the ideal solution here might be to use a shared smart pointer, where a count is kept to the number of modules referencing the object, and deletion happens when the last module relinquishes ownership. This is, of course, only one possible scenario, and the technique is not a "global" one (haha!).

Another possibility is the idea of passing the variable as a function parameter. The trouble with this is that you end up with a "ripple effect" where the interface of every object requiring knowledge of the object has to be changed to accomodate the extra function parameter. Sometimes this technique is suitable, but often the large-scale impact on object interfaces is no better than using a global variable. The solution you use will depend very much on how the variable is actually used within your application.

There are occasions when a global variable is the only serious solution to a problem, so it would be naive to dish out advice like "never use global variables". However, you should strive to consider the alternatives and really think whether you need them. Every unnecessary use of a global will make your application more brittle.

--
The placement of a donkey's eyes in its head enables it to see all four feet at all times.

Edited by - SabreMan on February 22, 2002 5:25:27 AM
Because I mostly think OO, my solution to avoid swarm of globals is OO. Like this :
  class CItem{...CItem * m_ciPrev;CItem * m_ciNext;};class CEntity{CItem * m_ciItemList;CEntity * m_cePrev;Centity * m_ceNext;virtual BOOL Move(void)=0;};class CPlayer :public CEntity{BOOL Move(POINT * dest);...};class CMonster :public CEntity{BOOL Move(POINT * dest, int mode);...};class CZone{...CItem * m_ciItemList;CEntity * m_ceEntityList;CZone * m_czPrev;CZone * m_czNext;};class CWorld{...CZone * m_czZoneList;};-> the only global CWorld * g_cwWorld;  

It is simplistic but many things can be handled like this.


DworD
DworD
quote:Original post by dword2002
Because I mostly think OO, my solution to avoid swarm of globals is OO. Like this :


There are two things in your post which I find contentious. Please don''t take this as I am picking on you, I just wanted to add my opinion to what you wrote.

Firstly, I don''t like this idea that people think OO, or that every computer program should be constructed using purely OO techniques. Not that you said exactly that, but it''s something I keep hearing and you reminded me of it. In short, there are some problems which can be expressed elegantly without using OO techniques, and so the issue boils down to "good design versus bad design" rather than "OO versus non-OO".

Secondly, I felt that your solution is a poor answer to the question of global variables. You''ve made a subtle move to having a globalised command class in your application, which you are using as a dumping ground for what was previously global. This is merely paying lip-service to the notion of avoiding global variables. OK, you only have one global variable, but you haven''t addressed the reasons of why you should avoid global variables.

This topic is closed to new replies.

Advertisement