Jump to content
  • Advertisement
Sign in to follow this  

When casting a class over a base class, anyway to tell if it is the right class?

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

Hi i'm using c++, and I've got a Base class and then I have the Draw, Input, Sound and many more classes inheirting off it. If I were to have a situation like so below: Base * b = someInstanceOfBaseOrDrawOrInputOrEtcClass; How would I check if the pointer is pointing to a Draw class instance and not some other? eg I would do a check if it is a Draw class first before doing this below, if it isn't I would just call an exception: ((Draw)b).someDrawFunc(); Thanks,

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by SiCrane
If your base class has virtual functions (and it should at least have a virtual destructor) you can use a dynamic_cast.


And check if the result is a valid pointer (i.e. != NULL)

Share this post


Link to post
Share on other sites
There shouldn't be any reason to do what you are asking. You should examine your design. If you want to call the base classes implementation of a function you can use: CDraw::Draw(...)

If you're storing "Draw-able" objects and ones that can't in the same list, split the list.

Happy Coding.

Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
Hi i'm using c++, and I've got a Base class and then I have the Draw, Input, Sound and many more classes inheirting off it.

If I were to have a situation like so below:
Base * b = someInstanceOfBaseOrDrawOrInputOrEtcClass;

How would I check if the pointer is pointing to a Draw class instance and not some other?

eg I would do a check if it is a Draw class first before doing this below, if it isn't I would just call an exception:
((Draw)b).someDrawFunc();

Thanks,


ummm, what do Input, Draw and Sound (and many more) have in common?

if you have to know the types of all the individual classes, then the Base class probably isnt going to work out.

im just wondering as to why you've decided to do it this way.

Share this post


Link to post
Share on other sites
thanks.

Quote:
Original post by rip-off
Quote:
Original post by johnnyBravo
Hi i'm using c++, and I've got a Base class and then I have the Draw, Input, Sound and many more classes inheirting off it.

If I were to have a situation like so below:
Base * b = someInstanceOfBaseOrDrawOrInputOrEtcClass;

How would I check if the pointer is pointing to a Draw class instance and not some other?

eg I would do a check if it is a Draw class first before doing this below, if it isn't I would just call an exception:
((Draw)b).someDrawFunc();

Thanks,


ummm, what do Input, Draw and Sound (and many more) have in common?

if you have to know the types of all the individual classes, then the Base class probably isnt going to work out.

im just wondering as to why you've decided to do it this way.


I was thinking of making each sub system of the program eg, sound, input etc into components that could be attached to the Main class, so if i didn't need sound, I could just not attach it to the Main class.

edit:
then for the input class you could add the components keyboard, mouse and/or joystick

and also for the render/draw class you could add components like ParticleSystem, MeshSystem etc

..im trying to find a good way to make my code more reusable, etc

Share this post


Link to post
Share on other sites
There are only two times that you need to cast:

1) Your design is wrong
2) The programming language is missing a feature

C++ has a lot of features so chances are it is the first case.

Share this post


Link to post
Share on other sites
Quote:
Original post by Glak
There are only two times that you need to cast:

1) Your design is wrong
2) The programming language is missing a feature

C++ has a lot of features so chances are it is the first case.


Yes I am indeed most probably doing something wrong ;)

Share this post


Link to post
Share on other sites
That's fine. Typically, you derive everything from class Interface (your Base), and implement the function getInterface() on Interface:


class Interface {
public:
virtual void addRef() = 0;
virtual void release() = 0;
virtual bool getInterface( char const * name, Interface ** oInterface ) = 0;

template< class T >
bool getInterface( T ** oT ) {
Interface * i;
bool ret = getInterface( typeid(T).name(), &i );
if( ret ) {
*oT = static_cast< T * >( i );
}
return ret;
}
};


The implementation for getInterface() in "Sound" would look something like:


bool Sound::getInterface( char const * name, Interface ** oInterface ) {
if( !strcmp( name, typeid(Sound).name() ) ) {
*oInterface = this;
addRef();
return true;
}
return false;
}


You can then use containment to attach functionality to the main program:


class Main : public Interface {
public:
void setInterface( char const * name, Interface * i );

template< class T >
void setInterface( T * t ) {
setInterface( typeid( T ).name(), i );
}
...
private:
std::map< std::string, IfPtr > ifs_;
};

bool Main::setInterface( char const * name, Interface * i ) {
ifs_[name] = i; // let IfPtr do its job
}

bool Main::getInterface( char const * name, Interface ** oInterface ) {
std::map< std::string, IfPtr >::iterator i = ifs_.find( name );
if( i != ifs_.end() ) {
*oInterface = (*i).second;
(*oInterface)->addRef();
return true;
}
return false;
}


Thus, you could create arbitrary components, and add them to the Main class, and then retrieve them back by interface name (if present). Using the Typeid versions makes the system (mostly) type safe -- if you put in a Sound interface pointer, you'll get back that pointer, static-cast to the right type. The static_cast<> makes sure that you have the right headers included to do the down-cast safely.

This is somewhat similar to how COM does dynamic type discovery, although COM also uses QueryInterface() for manufacturing new instances, which I think is the job of a specific factory function, rather than just QueryInterface. I e, I think your Sound interface should have a makeSoundInstance() member function which returned sound instances, rather than implementing that through overloading getInterface().

Also, for Glak: casts are sometimes useful -- such as in this case. There's no particular feature missing from C++ (unless you count truly dynamic dispatch), but this is pretty well-recognized as a case where down-casting makes sense.

Share this post


Link to post
Share on other sites
using typeid stuff is pretty much the same as casting, and indicates a problem. You should not need to get derived class information from something assigned to a base pointer. If you want to access Sound or whatever just make it global, either a global variable, global namespace, or global singleton. Some sort of global.

A lot of people come in here saying things like, I have B and D derived from A, I have a list of A and want to do a() for each A, b() for each B and c() for each C. They come up with the solution to do some sort of typeid thing through the loop, but really what they need are three lists. The same object can be in multiple lists, manipulated by the interface that it presents in each list.

Share this post


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

  • Advertisement
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!