Archived

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

Inheritance and Pointers...

This topic is 5303 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
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
You''re talking about virtual functions.

Make the function you want to call virtual in the character class.

Then override it in the derived classes.

Then you don''t have to cast, the compiler will route it to the derived class''s correct function.

Share this post


Link to post
Share on other sites
Hey mentat,

the only reason I think its better than rtti is because I noticed that rtti is a "compiler option" in VC++. This scared me a little because after that, it appeared that it may not be possibly supported on other compilers.. Also I was worried that it would make code more bloated, such as enabling "exception handling" (being another compiler option).!

Would anyone know if GCC supports RTTI?

I am 100% for RTTI, but I use my approach because:
a) I don''t know exactly how to use RTTI.
b) I am not sure its available on other (cheaper) compilers.

I admit that my approach does have a little overhead (function call, and IF statement), but I imagine you can just make the type variable public...

www.cppnow.com

Share this post


Link to post
Share on other sites
Use inheritance and virtual functions, that''s what they are for... what are you guys doing??

struct basePlayer_S
{
public:
float x,y,z; //position
float dx, dy, dz; //direction

public:
virtual void Draw(void) {};
};


struct Player_S : public basePlayer_S
{
void Draw(void)
{
//Draw player here
}
}

struct Monster_S : public basePlayer_S
{
void Draw(void)
{
//Draw monster here
}
}


Now, you can simply make a list of pointers to basePlayer_S, and fill that in with Monster_S, and Player_S''s, and just call ->Draw... and it will automagically call the CORRECT draw function, isntead of doing all checks for which type, etc, etc. Unless you have functions specific to each type, it is unnecessary, and if you do have functions specific to each type, you may want to ask yourself why you''re trying to treat them as the same entity type.

Share this post


Link to post
Share on other sites
Ready4dis, you totally missed the point. Elweren was referring to methods specific to the individual child classes and not inherited in any way from the parent class.

peace and (trance) out

Mage

Share this post


Link to post
Share on other sites
quote:
Original post by Mage2k
Ready4dis, you totally missed the point. Elweren was referring to methods specific to the individual child classes and not inherited in any way from the parent class.
Which is a bad idea... Klaxons should be sounding and loud speakers blaring "bad design bad design"

RTTI is there because they realized people are going to be doing what you want to do, and they might as well give you a somewhat safe interface for doing it...

...which doesn''t mean its RIGHT

Share this post


Link to post
Share on other sites
quote:
Original post by C-Junkie
Which is a bad idea... Klaxons should be sounding and loud speakers blaring "bad design bad design"


So basically, what you''re saying is that any object implementing more than one public interface is bad design?

Share this post


Link to post
Share on other sites