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

Started by
12 comments, last by LordShade 18 years, 4 months ago
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,
Advertisement
If your base class has virtual functions (and it should at least have a virtual destructor) you can use a dynamic_cast.
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)
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.
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.
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
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.
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 ;)
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.
enum Bool { True, False, FileNotFound };
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.

This topic is closed to new replies.

Advertisement