Jump to content
  • Advertisement

Archived

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

Elwren

Inheritance and Pointers...

This topic is 5673 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, I'm having a problem with calling functions from derived classes. In my program, I have a vector that contains pointers to a base class, vector(character*) myChar (i had to use parenthesis due to forum bug). There are two derived classes from character, player : public character and monster : public character. I create objects of these two classe by going:
character* myPlayer = new player;
character* myMonster = new monster;
So by making my vector a pointer to characters, I can add both myPlayer and myMonster to the same vector, which is what I want. However, lets say I want to access myPlayer within the vector and use some functions he has that are only in his class (not in the base class). Using iterators, it only allows me to use functions that are in the base class which doesn't help me at all. I know I can cast the iterator by giong
(player*)myVector[i]->playerFunction();
Yet, this seems like a hackish way to get through my problem. Is there something I am diong wrong? There has to be a way to access the player or monsters functions individually without making all the functions in the base class and simply overloading them within the derived classes or doing anyking of casting or what not. I hope this makes sense? Thanks for the help! [edited by - Elwren on June 5, 2003 4:10:51 AM]

Share this post


Link to post
Share on other sites
Advertisement
You''ll hafta cast.

There are some casting types... like dynamic_cast that either throw an exception or return NULL if the cast is invalid (rather than crashing hardcore -- but I suppose if you catch one exception you can catch them all)

I haven''t figured out a good way to NOT cast or something similar when using heterogenous arrays.

in C#, you''ve got a couple new things you can do:

if (variable is SomeType)
{

}

and

foreach(SomeType t in heterogenousarray)
{
// and it only loops through the ones that are actually of type SomeType.
}

Share this post


Link to post
Share on other sites
I assume what you want is something like this:
    for ( vector< character * >::iterator i = myVector.begin(); i != myVector.end(); ++i )
{
if ( (*i)->IsAPlayer() )
{
((player*)*i)->playerFunction(); // Note: the additional parentheses are necessary.
}
}

C++ provides ways of determining the type of a class. It is called Run-Time Type Identification (RTTI). The easiest to do it is this, but there are others.
    ...
{
player * const pPlayer = dynamic_cast< player * >( *i );
if ( pPlayer )
{
pPlayer->playerFunction();
...

Using RTTI makes code more fragile and inflexible, so you should make some attempt to avoid using it.

For example, if you also had separate player and monster lists, you wouldn''t have to worry about any of this. You would do player stuff with the player list, monster stuff with the monster list, and common stuff with the combined list.

Share this post


Link to post
Share on other sites
I guess the question is, why do you want to store everything in one vector? What is the benefit to you?

I would only do that if the operations I wanted to call on those stored objects were character-only operations.

But, xince you want to be able to call player and monster specific operations, your best bet would be to store them in separate vectors and here's why:

Let's say you store everything in one vector, so now you have a vector of characters. You want to loop through the list and call the player or monster specific operations depending on whether the object in the vector is a monster or a player. Well, that means that not only are you looping through every object, but you're also checking it's type twice . That's a large overhead, and frankly, far outweighs the benefit of storing everything in one vector.

Instead, just create two vectors and loop through each of them separately. You'll be doing the same number of loops as the previous example, but without the type checking. No casting and no dynamic_casts involved.

[edited by - fizban75 on June 5, 2003 9:16:44 AM]

Share this post


Link to post
Share on other sites
alternatively, you can create a new variable in the base class, call it CHARACTER_TYPE, which will be an enumeration. You can adda method to the base class, namely "TypeOfCharacter" which returns the character type, and is likely better than RTTI, and you will know programatically what type of class it is.

enum CHARACTER_TYPE {
CHARACTER_IS_PLAYER,
CHARACTER_IS_MONSTER,
};


... in your code:

...
...
character * c = vector-element...

if(c->TypeOfCharacter() == CHARACTER_IS_PLAYER) {
((player *)c)->specificPlayerFunctions();
} else {
((monster *)c)->specificMonsterFunctions();
};
...
...


www.cppnow.com

Share this post


Link to post
Share on other sites
superdeveloper:
why do you think yours is better than RTTI supplied by compiler?

in fact, I was about to post a similar question, but this thread seems to be quite related..

I know that casts are evil (like the original poster), but I have to use them anyway. I know that C style casts are more evil than C++ style casts, so I use dynamic_cast. but that requires enabling RTTI in the compiler in settings.. so, my question is, is it a bad thing to have RTTI? Both in design but more importantly optimized code sense. I guess RTTI brings some overhead in code size (logically), but does it have a speed overhead too? If so, how bad?

I used superdeveloper''s approach before, but now I am curious to know more about RTTI because it seems like super is implementing RTTI by himself in that example..

Share this post


Link to post
Share on other sites
quote:
so, my question is, is it a bad thing to have RTTI? Both in design but more importantly optimized code sense. I guess RTTI brings some overhead in code size (logically), but does it have a speed overhead too? If so, how bad?


quoted from http://www.camtp.uni-mb.si/books/Thinking-in-C++/Chapter08.html

quote:

Mechanism & overhead of RTTI

Typically, RTTI is implemented by placing an additional pointer in the VTABLE. This pointer points to the typeinfo structure for that particular type. (Only one instance of the typeinfo structure is created for each new class.) So the effect of a typeid( ) expression is quite simple: The VPTR is used to fetch the typeinfo pointer, and a reference to the resulting typeinfo structure is produced. Also, this is a deterministic process – you always know how long it’s going to take.

For a dynamic_cast(source_pointer), most cases are quite straightforward: source_pointer’s RTTI information is retrieved, and RTTI information for the type destination* is fetched. Then a library routine determines whether source_pointer’s type is of type destination* or a base class of destination*. The pointer it returns may be slightly adjusted because of multiple inheritance if the base type isn’t the first base of the derived class. The situation is (of course) more complicated with multiple inheritance where a base type may appear more than once in an inheritance hierarchy and where virtual base classes are used.

Because the library routine used for dynamic_cast must check through a list of base classes, the overhead for dynamic_cast is higher than typeid( ) (but of course you get different information, which may be essential to your solution), and it’s nondeterministic because it may take more time to discover a base class than a derived class. In addition, dynamic_cast allows you to compare any type to any other type; you aren’t restricted to comparing types within the same hierarchy. This adds extra overhead to the library routine used by dynamic_cast.



I would suggest that you not use RTTI in any heavy processing loops. It can be very handy however in other places. I personally use it for my plugin system. At loadup time, I open a bunch of dlls that contain specific plugin classes that are derived from abstract plugin types (i.e., plugin_model_ms3d and plugin_model_md3 derive from plugin_model which is derived from plugin; plugin_sound_wav and plugin_sound_au derive from plugin_sound which is again derived from plugin). The dll returns me a pointer to type plugin and then for each library I load, I use dynamic_cast to determine the type of plugin it is (plugin_model or plugin_sound). Very handy, but only something I''d do during the initialization of my application, never during the actual gameplay.

Share this post


Link to post
Share on other sites
why do you want to access functions specific to the player and not the base? Why are you deriving from base? Why are you storing a vector of base pointers if you really want a vector of players?

Share this post


Link to post
Share on other sites
Thanks for the help guys. For some reason I thought there was a non-cast solution to the problem. I guess having two vectors would be the wisest solution.

I wanted to put them in the same vector because it seemed fitting to put all the "characters" in one vector. For some reason I rememember my lab instructor in my college class saying that the compiler would somehow "know" what type the object pointer it was (whether a player or monster) and call the desired function. But maybe he was talkin about just overloaded virtual functions or something.

Anywho, thanks

Share this post


Link to post
Share on other sites
quote:

But maybe he was talkin about just overloaded virtual functions or something.


Yes, he was definitely talking about that. If you call the virtual function of the base class, but the object is actually a derived class, the function in the derived class will be called. If that''s all you need to do, then you can store them all in one vector.

However, if you want to call functions that are specific to players or monsters and that are not in the base class, you should store them as the derived classes in the separate vectors like we said.

Happy Monster Killing!

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!