Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ instanceof?

Started by evanofsky May 31, 2005 at 7:37 AM 23 replies 58k views
Original Post
evanofsky
evanofsky
A cookie for the first C++ programmer who knows what I'm talking about. N'eways, I'm trying to find out what type of derivative an object is. Like this: Base object; if(Base instanceof Derivative1) {do something;} if(Base instanceof Derivative2) {do something different;} I loved this feature in Java, but is there an easy way to do it in C++?
Toni Petrina
Toni Petrina
if (typeid(object) == typeid(Derived1)){  // do something}
So... Muira Yoshimoto sliced off his head, walked 8 miles, and defeated a Mongolian horde... by beating them with his head?

Documentation? "We are writing games, we don't have to document anything".
evanofsky
evanofsky
Hmm... didn't work. But you did understand it, so you still get the cookie.
darookie
darookie
Use dynamic_cast:
BaseClass * object = new DerivedA;if ( dynamic_cast<DeviredA*>( object ) )   // do somethingelse if ( dynamic_cast<DeviredD*>( object ) )   // do something else// ...


HTH,
Pat
Cygon
Cygon
It should work, as long as you've enabled RTTI (some compilers by default disable RTTI since it costs a tiny bit of performance and is seldomly used).

Another option would be
template<typename CheckType, InstanceType>bool isInstanceOf(InstanceType &Instance) {  return (dynamic_cast<CheckType *>(&Instance) != NULL);}if(isInstanceOf<Base>(pTheInstance))  cout << "mooh!" << endl;

but this requires RTTI as well. If I'm remembering right, Boost also provides a macro which can perform the check at compile time (of course, not including downcasts and ill-casted pointers ;))

-Markus-
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.
clb
clb
In C++ you can check the type runtime as follows:

// Suppose you haveclass Car;class Ferrari : public Car;class BMW : public Car;and then a function:bool IsFerrari(Car *c){   // check if pointer of type Car can be converted to type Ferrari   Ferrari *f = (Ferrari *)c;   if (f != 0)              return true;   else      return false;}int main(){   Car *f = new Ferrari;   Car *b = new BMW;   IsFerrari(f);  // returns true   IsFerrari(b); // returns false      delete f;   delete b;}

Fruny
Fruny
The preferred way (even in Java) would be to provide the appropriate virtual member function in the Base class, overriding it in the Derived classes:

class Base{public:   virtual void DoStuff() = 0;};class Derived1 : public Base{public:   virtual void DoStuff()   {      // Do something   }};class Derived2 : public Base{public:   virtual void DoStuff()   {      // Do something else   }};


Base* b = GetAnObject();b->DoStuff();


Now, if in spite of this good advice, you really want to figure out whether you have a Derived1, Derived2 or even something derived from one of those classes, you may use, not typeid, which will only check for exact type matches, but dynamic_cast, which will check whether the object you have is really a Derived1 object - or an object derived from that class.

note: clb, your version doesn't work, a C-style cast "works" unconditionally, whether it is right or wrong.

Base* b = GetAnObject();if( Derived1* d1 = dynamic_cast<Derived1*>(b)){   // do something with d1}else if( Derived2* d2 = dynamic_cast<Derived2*>(b)){   // do something with d2}


Also note that you either need to have a virtual function in your Base class, or "enable RTTI" for dynamic_cast (and typeid, for that matter) to work properly.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
evanofsky
evanofsky
Right, I use virtual functions for doing things differently, I just wanted other objects to find out what kind of object it is. For example, if the player hits the "board vehicle" button, it would loop through the objects, checking if each one is close enough to get in. However, I want it to make sure each one is a "Vehicle" before I try to get in it. Before now, the player was "boarding" the gun he was holding!


Thanks for the help guys!
Red Ant
Red Ant
Quote:
Original post by clb
In C++ you can check the type runtime as follows:
bool IsFerrari(Car *c){   // check if pointer of type Car can be converted to type Ferrari   Ferrari *f = (Ferrari *)c;   if (f != 0)              return true;   else      return false;}



Are you sure that works?? IMHO C-style casts never fail (i.e. return null) unless the argument itself is null also. You'd have to use the dynamic_cast operator to achieve that functionality. Feel free to correct me if I'm wrong.
Zahlman
Zahlman
Quote:
Original post by evanofsky
Right, I use virtual functions for doing things differently, I just wanted other objects to find out what kind of object it is. For example, if the player hits the "board vehicle" button, it would loop through the objects, checking if each one is close enough to get in. However, I want it to make sure each one is a "Vehicle" before I try to get in it. Before now, the player was "boarding" the gun he was holding!


Aha.

[google] "double dispatch".
DrEvil
DrEvil
Quote:
Original post by clb
In C++ you can check the type runtime as follows:

// Suppose you haveclass Car;class Ferrari : public Car;class BMW : public Car;and then a function:bool IsFerrari(Car *c){   // check if pointer of type Car can be converted to type Ferrari   Ferrari *f = (Ferrari *)c;   if (f != 0)              return true;   else      return false;}int main(){   Car *f = new Ferrari;   Car *b = new BMW;   IsFerrari(f);  // returns true   IsFerrari(b); // returns false      delete f;   delete b;}


No, This code does not work as you think it does.

Both calls to IsFerrari return true, C style casts always succeed.
pinacolada
pinacolada
Why not add a virtual function called "IsBoardable"?
Smack0007
Smack0007
You could do something like:

class Object{  virtual char* Type() { return "Object"; }};class Item : public Object{  virtual char* Type() { return "Item"; }};


Thats just a suggestion, type comparison would take a string comparison and would be slow.

You could also do:

#define OBJECT 0class Object{  virtual int Type() { return OBJECT; }};#define ITEM 1class Item : public Object{  virtual int Type() { return ITEM; }};


And with that you might try something like:

#define InstanceOf(x, y) ((x).Type() == (y))Object *obj = new Item();if(InstanceOf(*obj, ITEM))  cout<<"obj is an item."<<endl;


Just a suggestion.
- I don't pretend to know anything.Snowsoft
Daishim
Daishim
Or I suppose if you can spare an 32bit integer, I believe, for an enumeration or even an integer stating what the class is, might reduce the processing load, and only slightly increase memory usage.

I know only that which I know, but I do not know what I know.
Smack0007
Smack0007
This is true.
- I don't pretend to know anything.Snowsoft
Verg
Verg
Quote:
Original post by evanofsky However, I want it to make sure each one is a "Vehicle" before I try to get in it. Before now, the player was "boarding" the gun he was holding!


Don't take this the wrong way, but this sounds like an inheritance-heirarchy problem :)

If you have control over the base code, or any of the heirarchies... I'd suggest re-writing the classes... and not putting objects like Guns and Vehicles on the same inheritance branch.

Not that this helps your immediate problem much

:D

smart_idiot
smart_idiot
Quote:
Original post by ffx
if (typeid(object) == typeid(Derived1)){  // do something}


This is the answer, assuming you #include first.

clb: C style casts are evil, and your broken code proves it.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other
RDragon1
RDragon1
C-style casts perform reinterpret_cast<>, static_cast<>, and/or const_cast<> only.
Xai
Xai
adding IsBoardable and Board functions to the base object is the WRONG way to guy, leading to infinite interface bloat as each new feature / type is supported.

The only correct way I know to do stuff like this is the way COM did it ...which is that each of your object's implements interfaces for each feature it supports, and also provides some mechanism for a client to test if an interface is supported (in a general way that isn't interface specific).

In COM this is QueryInterface

In pure C++ this is dynamic_cast<>

most people I see use dynamic_cast, are doing it for the wrong reasons ... to do stuff that IS supposed to be in a base interface, or virtual ... or otherwise tie clients and objects together inappropriatly. But when used this way, as a means ONLY of investigating for the implementation of published interface classes, then it works just like COM (almost) ... and is a great way to support extensible features in clients.

For the people who don't know why you'd use it ... his example is perfect ... say your "GetCurrentSubjectObject()" function returns a function pointer to whatever GameObject your character is acting upon ... but you don't know what that type will be exactly ... all the client knows is that it is trying to "Active" the object ... so it checks for dynamic_cast(subject) ... and if it finds can, it calls Activate ... otherwise it returns an ActionNotSupported result (and beeps the user) ...
Aldacron
Aldacron
Quote:
Original post by Verg
If you have control over the base code, or any of the heirarchies... I'd suggest re-writing the classes... and not putting objects like Guns and Vehicles on the same inheritance branch.
:D


I disagree, as it's a very useful (not to mention common) approach for all objects in a game world to derive from a common base Entity/Actor/Pawn class. Many operations carried out on game objects are similar.

There's nothing wrong with comparing an object's type against another. Some people are quick to say that if you need to do so, your design is broken. Everything has it's place, though. Sometimes there are alternatives, but there is never a one-size-fits-all solution (as much as we would like for there to be). Perhaps type checking could be eliminated in this case by approaching the problem from a another angle.

For example, most (if not all) items in the game world (which should include vehicles) can likely be equipped, and conversely many game objects can equip other objects. By giving all equippable items functions to equip and drop other game objcts (and perhaps an onEquip function to be called on the object about to be equipped), you can then use context specific code to give the idea of 'equipping an item' a meaning appropriate to the item. In this case, equipping a vehicle could mean 'boarding' the vehicle. A gun could equip ammunition. Or you might want to use the term equip for something else, and call this 'attach' instead. Either way, it's a way of breaking several different actions down to one common method call. Of course, you still might need to do type checks to see if a particular object is equippable by another.

You might also use a message system, and each entity could process Game Messages such as GM_BOARD, GM_LOAD, GM_DRAW, and so on, ignoring the ones it isn't interested in. There's an example of such a system (in C) in Game Programming Gems 4 (based upon the Win32 message pump).

Anyway, there's more than one way to skin a cat. The best approach to take is the one that makes the most sense and doesn't hurt your performance too badly - and that can only be verified through profiling.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.