Archived

This topic is now archived and is closed to further replies.

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

This topic is 5776 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 =)

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
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.


No problem, that is the purpose of all that...
quote:

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".


Nobody can say that OO is always the BEST and ONLY solution, but OO always offers solutions. Because OO requires a good and rational structuration of problems, thinking problems with OO will produce a better understanding of them.
quote:

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.

Well, you are right; I didn''t give my opinion about global variables. When I began to program, I was using global variables for almost anything (like most of beginners do, I suppose). As the time and the projects were passing, I realized that this model was a problem and would prevent me for being able to achieve bigger projects because:

1) Global variables are confusing: after a long time you don’t always remember what the variable is for, who you have planed to use it, etc. Imagine when you have 40 or more globals ;

2) Global variables are dangerous: you can do anything anywhere with a global, even commit the worst (bogus assignations, wrong usage);

3) Global variables are inaccurate : a global is initialized at the beginning of the program even it is used in 0.1% of the code ;

4) Global variables are often the symptom of a bad problem analysis: globals are just like saying: the problem can not be think as a system, just like a myriad of standalone phenomenon’s.

For all the reasons (and much more), I am using OO coding. I don’t want to be proselyte, but, to my opinion, it is a good way to think.

DworD

Share this post


Link to post
Share on other sites
quote:
I''ve actually been wondering the same thing, how do the "big boys" avoid a lot of global variables? Anyone know?


I tend to declare an application class that holds all the functions and variables of my program.

  
class CApplication
{

public:
CApplication();

BOOL Create();
BOOL Run();

SOMETYPE SomeVariable;

CDisplay *m_pDisplay;

};


I tend to modularise everything. Eg for display, I''ll have a CDisplay class that holds all the routines to draw stuf etc..

But that''s just me. I hate globals.

Oli



All the best problems start with C

.:: K o s m o s E n g i n e ::.

Share this post


Link to post
Share on other sites