• Advertisement

Archived

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

Can't find ANY info about how to get data from one part of an OOP to another.

This topic is 5551 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

It''s driving me nuts. I''ve read three books on the subject, and none of them address the problem specifically, but rather ramble on and on about abstraction and encapsulation and other useful yet irrelevant subjects. All about how hiding data is so great, yet I can''t hide every variable from every other variable lest my program become inoperable, but they give no hints as to the proper ways to share data. I am left with a firm conviction that information hiding is good, but have no clue how to share the information that it is neccesary to share, or how to make classes know how to call other classes. Their example programs aren''t even any help, since they seem to always be some lame finance program that has no complex data structures and no complex output to the screen. For instance, I am currently in the concept stages of a simple hack''n''slash RPG. I''m trying to figure out what kind of code structure I''m going to use, and I''ve pretty much decided OOP is the way to go. It''s go so many nice features. So I lay out which classes I need. Well, it''s pretty obvious I''ll need classes for the game world, the current map, the player, monsters, items, ect. And a class to put everything on the screen, and to a class to recive input from the player, and a class for file IO. But these classes are not all self-sufficient entities. The player class needs to know about the game world. The monsters need to know about the player. The player needs to know about items. Most importantly, the display needs to know everything, and everything needs to be able to get input. I can''t figure it out... The only way it could work at all is if all the instances of classes were global variables and every class knew the name of every other class, hardcoded into it''s methods. But unless I misunderstand my books, this goes against all the principles of information hiding and encapsulation. If every class knows all about every other class, then what''s the point of using OOP at all? Any help would be greatly appreciated.

Share this post


Link to post
Share on other sites
Advertisement
Ever consider using singletons? There is a GD article somewhere around here, but if you are serious about OO Programming in C++ (I assume you are using C++), I suggest you read the book "Modern C++ Design". Either way, singletons use a static method to access an instance of the singleton, and also maintain that only one instance of the class ever exists. So from anywhere in your code you could access the object.



_______________________________
It''s not reality that''s important, but how you perceive things.

A man''s reach should exceed his grasp.

Share this post


Link to post
Share on other sites
What I would suggest is to not make your game too general. A game has several components (input, audio, graphics) -- so why is it bad design or not a good idea to allow one class the ability to "know" about some other class?

Share this post


Link to post
Share on other sites
I''m trying to use a system with a CGame class that contains instances of the other main classes - CInput, CGraphics, etc. Cgame knows about and interfaces with the other classes, and those don''t know about each other.

I haven''t gotten very far with it yet, so I''m not sure how well it''ll work, but it''s a thought.

Share this post


Link to post
Share on other sites
First off. Good work Gwahir.
I can tell your new to programming, but youll make an awesome programmer. I''m sure of that.
Taking the time to formulate a good question, and do your research as you did is the most important thing. (If only more people on these forums would do just that, we''d all be a happier bunch.)

I found myself asking those same questions when I was learning about OOP.

What people mean when they talk about Abstraction, and Encapsulation is clearly seperating details and implementation from the purpose.

For example, say you have a class that represents a creature in your program. (don''t mind the psuedo-code )

If it was a C style structure, it might look like this:

struct Creature {
int health;
char* name;
};

The C++ style, object oriented equivalent would look like this:

class Creature {
public:
int GetHealth();
void ChangeHealth(int Delta);
string GetName();
void SetName(string Name);

private:
int m_health;
int m_name;
}

The purpose of the variables, is to keep track of a name, and a quantity of health for a creature. _HOW_ the name is stored, and how health is stored should never need to be known by another class.

If another class wants to find out the health of a creature, it does SomeCreature->GetHealth() and gets an int.
However, SomeCreature doesnt need to store an int internally, it could in fact keep the health in a database, as a string. Its all up the the implementation of Creature.

So whats all this shit mean?

You want program code to look like:
Creature SomeCritter;
cout << SomeCritter.GetName();
SomeCritter.ChangeHealth(-25); // Wound the critter

Never like this:
Creature SomeCritter;
cout << SomeCritter.m_name;
SomeCritter.m_health -= 25;

They may look the same at first, but the first one is the object oriented way.

-------

The names of methods shouldnt change ever really (provided you picked em right the first time hehe).
However, the details inside can change alot. So don''t worry about ''hard-coding'' the method names. Thats what there for.

...
The name and parameters of a method is its interface.
The code block that is executed when called is the implementation.

Interfaces should seldom change, implementation changes all the time.
...

-------

So now your probobly thinking "okay, I understand that.. So how do I organize all these little instances of my neat, properly written clases?"

Ha.. This is where the fun begins.
Perhaps you have one or two global variables, or one or two singletons.
C++ isnt java. You need _some_ global shit. So don''t be scared to have a few things global (but I do mean a FEW).

Inside those global objects, youll have either arrays, vectors, or maby something like trees populated with objects.

Objects communicate between eachother by sending events. (In the real world of C++ ... ''events'' are actually method calls)

-----------

Hope that helps you understand,
Feel free to ask me to clear up any vauge parts. (There is probobly a ream of them)

NOTE to potential flamers:
Drop that flamethrower. I am not saying OOP is good, or bad. I''m not saying globals are good or bad. I am not promoting or insulting Java, or C++. I''m not telling kids to play in traffic. I am just attempting to smash some confusion.
So please, dont flame me on details. Its just the idea that matters after all.
Thanks!
- Jacob

Share this post


Link to post
Share on other sites
Hey cool, I''m doing the same thing

Only problem I''ve really come accross is putting to much stuff into my COpenGLSubsystem

I think thats mostly because I''m still at renderer development stages, so I need a lot of test info in there. Eventually I''ll ship it out to seperate classes and stuff.



"With my feet upon the ground I lose myself between the sounds and open wide to suck it in, I feel it move across my skin. I''m reaching up and reaching out. I''m reaching for the random or what ever will bewilder me, what ever will bewilder me. And following our will and wind we may just go where no one''s been. We''ll ride the spiral to the end and may just go where no one''s been." - Maynard James Keenan
Name: TheBlackJester
Team: Wildfire Studios

Projects
O A.D.
The Last Alliance

Share this post


Link to post
Share on other sites
quote:
Original post by Gwahir
But these classes are not all self-sufficient entities. The player class needs to know about the game world. The monsters need to know about the player. The player needs to know about items. Most importantly, the display needs to know everything,



Could the world ask the player object what it needs to know?
Could the world tell the player object what has been done to it?
Could the monster ask the player object what it needs to know?
Could the monster tell the player object what it has done to it?
Could the player ask each item about its properties?
Could the player tell each item what it is doing to it?
Could the display ask each displayable object how it looks?

This is actually not an OOP problem. It''s a large-scale project problem. The issue is circular dependencies, and it''s quite possible to run into the same issue in a strictly procudural design as well as OOP. I highly recommend reading Lakos''s "Large-Scale C++ Design"; he gives many methods of fixing circular dependencies.

quote:

and everything needs to be able to get input.


Ah, input is trickier, but there is a way to do it. I don''t know exactly what kind of input you''re using, but you probably need the "Visitor" design pattern.

Making everything global is not something that will scale well with project size. And I recommend against using singletons as a panacea.

HTTP 500 strike 1..

Share this post


Link to post
Share on other sites
The way I''m solving this sort of problem is by having a bunch of managers, or just one large manager. It''s a gateway of sorts to other classes and their functions.
But to do this I need to declare the manager as an extern in every file that needs to access the manager, so this solution is not as perfect as I want it to be, but it works pretty well and you can track things through classes without a problem.

You can also easily create a function like GetHwnd() within manager, this function then points to another GetHwnd()-function in the class that currenly has the Hwnd. So if you ever need to move the Hwnd(or whatever it is) you just need to rewrite one line of code inside the manager instead of repointing every line that accesses the variable/function of your choice. Hope I makes some sense, I''m a bit tired right now


Anyway, to the main benefit of this, if I created a creature in a class handling NPCs which in itself is a subclass to a game-class and then wanted to access the world-class from my creature it would look something like this:

(inside the creature-class)
(from Game->NPC->Creature)manager->Game->World->Whateverfunction();
If I want to access a creature from World it would look like this:
(from Game->World)manager->Game->NPC->Creature->GetState();

This strings become quite lengthy at times but you can copy the location of a class into a pointer to cut it down in size, this pointer is declared and created within the class you want to have the shortcut. So the long string above would instantly be cut down to Creature->GetState within the world-object.
If done right this system is quite good but it takes some planning to get right.

Share this post


Link to post
Share on other sites
Thanks guys, I'm glad I decided to ask here. Learned about as much in your posts as I did in reading a whole book full of techno-babble. Which has it's place, but it certainly isn't conductive to learning.

I'd like to clear up a few things, however...

quote:
Objects communicate between eachother by sending events. (In the real world of C++ ... 'events' are actually method calls)


Ok, I think I see that. But a class cannot call another class's method unless it knows the name of the other class... Let me try to show a quick example of my problem in the interaction between three classes: CPlayer, CMonster, and CInput.


  

class CPlayer
{
public:
void AttackMonster(CMonster &monster);
//other junk


private:
int damage;
//other junk

}

class CMonster
{
public:
void TakeHit(int damage);
//other junk


private:
int armor_value;
int hitpoints;
//other junk

}

class CInput
{
public:
void CheckKeyboard(void);
//other junk


private:
//other junk

}

void CPlayer::AttackMonster(CMonster &monster)
{
monster_ID->TakeHit(damage);
}

void CMonster::TakeHit(int damage)
{
hitpoints -= (damage - armor_value);
}

void CInput::CheckKeyboard(void)
{
if(keydown(x))
{
Player->AttackMonster(Monster);
}
}



So there I have my classes. That, to my best understanding, is a perfectly legitimate setup. But here comes my problem. In order for CInput::CheckKeyboard to function correctly, it needs to be able to acces the variables 'Player', an instance of CPlayer, and 'Monster', an instance of CMonster. How?

To have 'Player' and 'Monster' be global would work, but would quickly become cluttered and difficult in a large program.

To have 'Player' and 'Monster' be members of CInput would work, but would become totally unfeasable in a larger program, because there would be other classes besides CInput that would need acces to those variables.

And I can't think of any other way to do it. So how would you do what I tried to do in that code example?

And Stoffel, are you the same Stoffel from the Heavengames KoRT forum?

[edited by - Gwahir on December 6, 2002 3:51:22 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I would move this code out of CInput:

if(keydown(x))
{
Player->AttackMonster(Monster);
}


Instead, CInput could report what happened to the game world, say CGame:

if(keydown(x))
{
pGame->OnPlayerAttackAction();
}


CGame then determines the following:
If there is more than one player-controlled character, which one is active (has the focus)?
Is there a monster in front of player? If so, send that monster to the player''s method:

CPlayer* pCurrentPlayer = GetCurrentPlayerCharacter();
CMonster* pMonster = GetMonsterInFrontOfCharacter();
if (pMonster != NULL && pCurrentPlayer != NULL)
pCurrentPlayer->AttackMonster(*pMonster);


So, CInput has a pointer to CGame; or CGame can be a singleton, and CInput accesses it through GetInstance(). CGame needs to know about CPlayer and CMonster, but that seems logical...how could the game NOT know what it contains?

This also allows CInput to support customized key layouts...x could be mapped to "RunLikeHell()" instead of attack, simply by changing which function is called in pGame.

Share this post


Link to post
Share on other sites
I think youa re partially getting confused with the difference - or lack thereof, between A) knowing about a class, B) having access to a particular object (instance) of a class, C) having access to an object''s internal data ...

So here goes.

A Class such as CPlayer, will know about a class such as CMonster, in the sense that it''s member functions will call member functions of CMonsters, exacltly like in you example (a given player object attacks a given monster object (which is passed as a paramter to AttackMonster). So the CPlayer class knows about the CMonster class, but does NOT know about individual CMonster objects (until they are passed as parameters to functions) ...

Now the input guy is different. An input handler is some central object / singleton (because the app needs to be able to route keyboard messages to the keyboard handler), but how does the keyboard handler know where to send his messages? Well, this is usually done by having the keyboard handler having a pointer to the CGame object ... which in turn has pointers to the current CPlayer objects, and the active CMonster objects, etc ...

so the keyboard handler gets an ''x'', so it callssomething like

game->CommandAttack();

which looks at it''s local variabls and might do something like:


  
CMonster *currentTarget = FindNearestMonster();
if(player->IsTargetInRange(currentTarget))
player->AttackTarget(currentTarget);


and perhaps their is a keyboard command ''s'' that calls:

game->CommandSelectNextWeapon();

which in turn calls

player->SelectNextWeapon();

which changes the players internal values, so next time an attack, or a draw, or whatever is done ... the functions

player->GetCurrentWeapon();
and
player->AttackMonster(currentTarget);

will return the new weapon choice, will different graphics, damager, etc ...

I''ll try to come back later and add more ...

Share this post


Link to post
Share on other sites
Ok, I think I see... So to summarize what you both have said:

Rather than having classes interact directly with eachother, have them interact with a superclass that would in turn interact with the true target of the action. Thus, normal classes don''t have to know about any other class except the superclass, but the superclass itself does know about everything. Of course, in a larger/more complex program classes and superclasses would be layed out in a tree-type structure.

quote:
I think youa re partially getting confused with the difference - or lack thereof, between A) knowing about a class, B) having access to a particular object (instance) of a class, C) having access to an object''s internal data ...


Yes, I was a bit... So let me get these straight.

A. Any class can know about the interface of any other class, and this is in no way a bad thing.

B. Having access to particular instances of a class is neccesary, but should be done in a logical manner, and shouldn''t share that knowledge more than neccesary. (same rules that apply to variable scope in modular programming)

C. No class should mess with the inner workings of any other class in any way, shape or form. This is the primary meaning of the concepts of encapsulation and abstraction.

I actually think I got it.

*fires up IDE to try it out*

Share this post


Link to post
Share on other sites
quote:
Original post by Gwahir
And Stoffel, are you the same Stoffel from the Heavengames KoRT forum?


Nope.

Share this post


Link to post
Share on other sites
To avoid the headaches of rewriting class interfaces over and over again, take some time away from the IDE with a pencil and paper and try drawing some block diagrams. You know, a square representing a class, and connecting lines representing how they "talk" with eachother.

Share this post


Link to post
Share on other sites
quote:
Original post by Hollower
To avoid the headaches of rewriting class interfaces over and over again, take some time away from the IDE with a pencil and paper and try drawing some block diagrams. You know, a square representing a class, and connecting lines representing how they "talk" with eachother.

Amen. I like to take a walk and brainstorm, then jot some of my thoughts down when I get home (on pencil & paper).

Then I''ll whip open a new file in VC and write comments for everything in my diagrams. Usually design flaws should show up in this stage. Then I will code the comments, leaving well documented code in my wake.

And BTW, don''t use mspaint for the jotting. It''s hard. I''ve tried.

Share this post


Link to post
Share on other sites
>>And BTW, don''t use mspaint for the jotting. It''s hard. I''ve tried.<<

Speaking of which, does anyone know of a good program to use for whipping up class hierarchies? I don''t mean some big bloated UML monster, just a way to quickly make up a tree-like hierarchy of classnames, and *possibly* the ability to list some methods for the classes as well.

I do the jotting it down on paper thing a lot too...and it works pretty well for the most part. But, I wish there was a way to do something similar *quickly* on the computer. It''d be nice because I often like to rename things a lot and/or re-arrange the hierarchy of stuff, and that''s hard to do on paper.

-John

Share this post


Link to post
Share on other sites

  
class Creature {
public:
int GetHealth();
void ChangeHealth(int Delta);
string GetName();
void SetName(string Name);

private:
int m_health;
int m_name;
}


is not a proper c++ way of doing this, you are forgetting the const keyword.. should look like this to be const correct and more optimizable by compiler. Also pass the string by const reference for gods sake to avoind data duplication and memory handling internally by stl ( im assuming stl is used here )
Also return the string by const reference... :-)


  
class Creature {
public:
int GetHealth( void ) const;
void ChangeHealth( const int Delta);
const string& GetName( void ) const;
void SetName(const string& Name);

private:
int m_health;
int m_name;
};


[Insert cool signature here]

Share this post


Link to post
Share on other sites
quote:
Original post by Gwahir
Rather than having classes interact directly with eachother, have them interact with a superclass that would in turn interact with the true target of the action. Thus, normal classes don''t have to know about any other class except the superclass, but the superclass itself does know about everything.

Uh... yes and no.

This ''pattern'' is good for some systems but not for others. It''s often referred to as the ''Mediator'' pattern (name from the ''Design Patterns'' book) because 1 object acts as a mediator between the others. Other literature simply calls this a control class (which encapsulates action), as opposed to a boundary class (which encapsulates a user or interface) or an entity class (which encapsulates an object within the system). But no, it''s not The way. It''s perfectly acceptable to have numerous objects know about each other. In object oriented programming, the objects are the system - they''re not just glorified data structures that you manipulate from outside.

Minimising dependencies between classes/modules/whatever is a good thing, no matter whether you''re using OOP or not - however putting all the control flow into one class is not necessarily a good way of doing this, as now that ''superclass'' as you call it is dependent on every single other class.

You seem to be coming from the standard programming paradigm of viewing everything as procedures and data, where the aim is to operate on data to achieve the results. This commonly leads to the dilemma of ''how do I change things in class X if it''s all encapsulated?'' The simple answer is that, instead of thinking about how you affect class X from other classes, think about what kind of actions class X will do in its lifetime, and implement functions for each of those accordingly. It''s the move from code like this:

int h = creature.GetHealth();
creature.SetHealth(h - 10);


to code like this:

creature.Injure(10); 


Think about it.

quote:
A. Any class can know about the interface of any other class, and this is in no way a bad thing.

A class should know about enough other classes in order to operate effectively and to do its own job, and no more. Fewer is better, because it reduces dependencies, but reducing it to zero and then having another object (such as a mediator) perform all the important work is just as bad because all you''ve done is invert the dependency.

quote:
B. Having access to particular instances of a class is neccesary, but should be done in a logical manner, and shouldn''t share that knowledge more than neccesary. (same rules that apply to variable scope in modular programming)

Sure. Everything is on a ''need-to-know'' basis. Again, this is largely to eliminate dependencies.

quote:
C. No class should mess with the inner workings of any other class in any way, shape or form. This is the primary meaning of the concepts of encapsulation and abstraction.

Yep. This is to minimise dependencies. *echo*

Computer source code is a brittle thing. Throughout its entire lifetime it is changed, and therefore one of the most pressing problems facing a programmer is how to effectively manage that change. What you don''t want is to change 1 thing and have that little change make it necessary to make 100 other changes elsewhere. Encapsulation reduces the damage done by such changes by ensuring that alterations are kept local. Abstraction reduces the damage done by such changes by ensuring that implementational details - which are most prone to be changed - are hidden from the objects that indirectly use them. Polymorphism reduces the damage done by changes to the code by presenting an interface that stays static even when the object in question is of a different type.

The above is a simplification, but in essence all these buzzwords are all variations on the same theme - concepts that make source code more resistant to change and more sturdy.


[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]

Share this post


Link to post
Share on other sites
I decided to drop-in here - Gwahir, you''re missing a key component of OOP.

You need to define interfaces. They should contain all pure-virtual methods, and then classes such as CMonster will implement various interfaces. The C in the class name does not stand for ''class'', it stands for ''concrete'' as opposed to prefixing it with an I for ''interface''.

IGameEngine
IGameEntity
IPhysicsEngine
IPhysicsEntity
IGraphicsEngine
IGraphicsNode
IAudioNode
IAudioEngine

Those are put into seperate headers, and then anything that needs to use (or provide) those services include the header files.

IPhysicsEntity is a contract that a class must fulfill, in order for the physics engine to manipulate instances of that class. This keeps the concrete implementations rather ''ignorant'' of each other.

IPhysicsEngine
{
virtual AddEntity(IPhysicsEntity*)=0
virtual Tick(virtual_time now)=0;
//...
};

IPhysicsEntity
{
virtual void ForceApplied(vector3D force_vector)=0;
virtual void Collision(IPhysicsEntity* collided_with, point3D point_of_collision, virtual_time when)=0;
//...
};

CPhysicsEngine : IPhysicsEngine
{
//implement IPhysicsEngine
};

CMonster : IPhysicsEntity, IGraphicsNode, IAudioNode
{
};


With C++, you can provide partial implementations for any given interface (often templates are useful for this) and re-use it without multiple concrete classes. e.g. You may want a CPlayer class along with that CMonster one, but 80% of their implementations may be the same.

Share this post


Link to post
Share on other sites
Ah... I think I understand...

So for my hypothetical program, I would have ''CMonster'' and ''CPlayer'', as I did before, but I would also have both inherit an ''IObjectThatMoves'' class, since both would probably move in much the same way... Also, I could expand it even further and have an IObject class that ''CMonster'', ''CPlayer'' and ''CItem'' all inherit, because they are all physical objects and have a position in space and time within the game.

Cool.

The only problem I can see with this is if two of the inherited classes share a method name... From the examples in my books, things can get very messy very quickly.

Share this post


Link to post
Share on other sites
quote:
Original post by Gwahir
The only problem I can see with this is if two of the inherited classes share a method name... From the examples in my books, things can get very messy very quickly.

But that is how the interface works... derived classes have the same method name, but slightly different behaviour. The idea is that the ''outside world'' only needs to know the interface (ie. the method name, defined in the base class) and the individual classes take care of the differences by executing the correct function for each object.



[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]

Share this post


Link to post
Share on other sites

  • Advertisement