• Advertisement
Sign in to follow this  

C++ - a class, a void* and a new object

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

I have a function in a class like so (this is a trivial example but my real project has a purpose for the void pointers)
bool Monster::DataResponse( int messageType, void *messageValue )
{
  // return units x and y position in the messageValue pointer
  point *unitPosition = new point; // ToDo: delete
  point->x = xPos;
  point->y = yPos;
  messageValue = (void*)point;
  return true;
}
Now when the program calls this DataResponse function from another class and casts the messageValue back into a point the x and y values are not what is expected Why?

Share this post


Link to post
Share on other sites
Advertisement
There are better ways to do this, but the direct answer to your question is that you aren't storing anything into messageValue. You would need something like this, instead:


bool Monster::DataResponse( int messageType, void **messageValue ) // note the '**' (pass in the address of messageValue)
{
// return units x and y position in the messageValue pointer
point *unitPosition = new point; // ToDo: delete
point->x = xPos;
point->y = yPos;
*messageValue = (void*)point; // note the '*' (store point at the address pointed to by messageValue)
return true;
}

Share this post


Link to post
Share on other sites
"void *messageValue" should be passed as "(void*) &messageValue" or "void **messageValue"

Share this post


Link to post
Share on other sites
Pass a reference: void *&messageValue. Otherwise you're just changing a copy; the original pointer that the calling code used is still the old value.

Also, what is this purpose for the void pointers? I don't believe you.

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
Also, what is this purpose for the void pointers? I don't believe you.


In case he wanted to do something like this [grin] Hides in corner

Share this post


Link to post
Share on other sites
Or my heterogeneous untemplated [well, sort of templated] linked list class *ducks*

OH, you mean good purpose...

Share this post


Link to post
Share on other sites
Thanks all i got it.

Quote:
Original post by smart_idiot
Also, what is this purpose for the void pointers? I don't believe you.


I need to pass data back to the parent class but that data is different for every monster.

ie. all game objects derive from a base class (funnily enough called GameObjectBase)

This has common functions like Draw (all game objects are renderable in this game) and Animate (steps forwards a frame). All the derived game objects are stored in a vector so i can just call (psuedocode)
for all elements of the vector
{
Animate
Draw
}



Now there comes the problem of input, some objects respond to keyboard input some only to mouse some to both and most objects return data that is valid only to them (the hero for example returns a display inventory message along with a pointer to his inventory when clicked).
I want to make the game so that when i get a mouse click i can go


messageType = MOUSE_CLICK;
messageValue = point;
for all elements of the vector
{
if ( object.DataResponse( &messageType , messageValue ) // true if object was the one clicked
{
if ( messageValue != NULL )
processResponse( &messageType , messageValue ); // a function that does the returned request
break;
}
}


That way all objects can still inherit the one base class (easier for rendering) despite the differences in the way they respond to the different types of input.



If you can think of a better way of doing this without voids then tell me :)

Edit: my topmost example should have had int *messageType as a parameter so that i can pass a different messageType back again.

[Edited by - Pacifist on April 26, 2005 10:08:02 PM]

Share this post


Link to post
Share on other sites
ewww...

I use functors for this. [though ironically enough, the functor class I've used for all my gui-stuff in the past stores the parameters in the void* heterogeneous semi-templated linked list class....]

Essentially...

[though please please someone correct me if the STL adapaters allow for better functor goodness...]

[and sorry for the length; I need the practice]



struct action{
void operator()()=0;
virtual ~action(){}
};

template <typename T>
struct global_action:public action{
T t;
void operator()(){
t();
}
global_action(T &some_action):t(some_action){}
};

template <typename F>
action *make_global_action(F f){
return(global_action<F>(f));
}


struct keybinding{
keycode key; // define keycodes somewhere...
action *bound_action;

void activate(){
if (bound_action){
(*bound_action)();
}
}
bool match(keycode k){
if (k==key){
return(true);
}else{
return(false);
}
}
keybinding(keycode k, action *inaction):key(k),bound_action(inaction){}
~keybinding(){delete bound_action;}
};

// And similar for mousetargets!

struct GameObjectBase{
vector<keybinding> kbinput; // or, use a fixed array or map
// if you expect this to be
// usually full.
mouse_target onleftclick;
mouse_target onrightclick;

virtual void animate();
virtual void render();
// stuff!
};





Then, you just need to figure out which object takes the input, and activate the bound functor. For the hero example, the hero should post the message "open hero_inventory here" [to a queue where it's later picked up] from the bound function, not return it.

In the way I've done it in the past that is...

Eh. That's a terrible example. Something like that...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I'm reading up on functors now although it seems way more complex than the way i do it.

My way i have all game objects in a vector which is inside the main game class.
Then i send the mouse events to all those objects to find what object was clicked.

Then if the object returned a message such as SHOW_INVENTORY in messageType i create a new InventoryDisplay object in that vector with messageValue(a void*) pointing to the inventory items.
However if the object returned a message such as SHOW_STATS in messageType i create a new StatsDisplay object with messageValue pointing to the stats.

See the above stuff is my problem, the objects themselves are the ones that decide what to request/return if they have been clicked. The hero doesn't always return show inventory on a mouse click and a monster doesn't always return show stats on a mouse click. If the monster is dead for example i'd prefer the monster to display an inventory screen rather than a stats screen when he is clicked, with my way he can easily do this.

So i can't really bind an open inventory function to the hero object, the hero object itself needs to determine what to request from the main class in the returned values.

Share this post


Link to post
Share on other sites
Well, one simple way to avoid the voids would be to create a MessageBase class. Then derive each specific message from that class. Then you would pass around MessageBase pointers instead of void pointers.

Share this post


Link to post
Share on other sites
Dave, I actually have this.
But what about the different types of structs the messages need to return? This is why i needed the void*.


I found another solution though, one that doesn't require a void* :)
I have a main game class, one that holds and runs the vector<> of all gameObjects.
In my main game class i also have functions such as showInventory that adds an inventory object to the gameObjects vector (inventory is a gameObject).

Now my game objects also contain pointers the main game class (the circular referencing tutorial is good) and the showInventory/showStats functions are public.

So when my game objects get a mouseMessage they simply call the functions they require directly :)



Link to circular referencing tutorial: http://www.gamedev.net/reference/programming/features/orgfiles/page3.asp

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I'm reading up on functors now although it seems way more complex than the way i do it.


maybe more complex, but it's far far far less tedious than that big switch() statement you need for the different messages. [Heh, I had that big switch statement all over the place when using void*'s too much]

Quote:

My way i have all game objects in a vector which is inside the main game class.
Then i send the mouse events to all those objects to find what object was clicked.

Then if the object returned a message such as SHOW_INVENTORY in messageType i create a new InventoryDisplay object in that vector with messageValue(a void*) pointing to the inventory items.
However if the object returned a message such as SHOW_STATS in messageType i create a new StatsDisplay object with messageValue pointing to the stats.

See the above stuff is my problem, the objects themselves are the ones that decide what to request/return if they have been clicked. The hero doesn't always return show inventory on a mouse click and a monster doesn't always return show stats on a mouse click. If the monster is dead for example i'd prefer the monster to display an inventory screen rather than a stats screen when he is clicked, with my way he can easily do this.


And? In my above example, in monster->die() change the functor to "inventory" rather than "stats". Or better yet, change monster to dead_monster, which does the right thing [rather than going if monster->dead everywhere...

Though realistically it'd be easier if you didn't tie objects with their representation...

Quote:

So i can't really bind an open inventory function to the hero object, the hero object itself needs to determine what to request from the main class in the returned values.


Then bind a "hero_clicked_on(hero *)" function, which determines what message to post. Provide a universal interface to the input-handler.

Quote:

Dave, I actually have this.
But what about the different types of structs the messages need to return? This is why i needed the void*.


Eh? Inheritance!



struct MessageBase{
string who_sent_me;
string retrtype()=0;
MessageBase(string s):who_sent_me(s){}
virtual delete(){}
};

struct InventoryCreationMessage:public MessageBase{
string retrtype(){return(string("Inventory Creation"));}
Inventory *inv;
InventoryCreationMessage(Inventory *what_to_open,string sender):inv(what_to_open),MessageBase(sender){}
};

struct StatsCreationMessage:public MessageBase{
// ...
// ...
};




And this way, you can always return a MessageBase *, not a void pointer. Granted, this still yields a giant switch statement as you try to parse through types. Blech!

Quote:

I found another solution though, one that doesn't require a void* :)
I have a main game class, one that holds and runs the vector<> of all gameObjects.
In my main game class i also have functions such as showInventory that adds an inventory object to the gameObjects vector (inventory is a gameObject).

Now my game objects also contain pointers the main game class (the circular referencing tutorial is good) and the showInventory/showStats functions are public.

So when my game objects get a mouseMessage they simply call the functions they require directly :)



circular referencing? Good? Heh, tell me that again after you make your load/save game functions or networking code for this game.

*shrug* void pointers invariably lead either to switch statements, which are tedious and require code changes in 2+ places every time you add a new message/class/type. Likely source of bugs.

OR they require you to make assumptions about what you're being passed, which is an even more likely source of bugs.

I know you won't really listen, or think these little things easily overcome by meticulous programming. God knows I didn't when folks told me. Just try and remember this later...

Share this post


Link to post
Share on other sites
Quote:

circular referencing? Good? Heh, tell me that again after you make your load/save game functions or networking code for this game.


I only use the circular referencing to get to the main classes functions. So when my hero needs to display the inventory he can simply go

if mouse clicked on me
{
if ( bNewItems )
mainGameClass->showInventoryScreen // Adds an inventory screen object to the main game class
else
mainGameClass->showStats // Adds a stats screen to the main game class
}


Too easy, and no more void pointers/massive switch statements :)
Also i can't really see how that would affect loading/saving, it's the functions i'm using not the storage.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement