how to tell what class an object is in c++

Started by
61 comments, last by krez 22 years, 2 months ago
let''s say i have a virtual base class, CThing, from which is derived CItem, CWeapon, CArmor, et cetera... some other classes are derived from these derived classes as well. i use a pointer to the base class for an inventory listing (as all the specific details aren''t important, i just want a quick listing). is there a way to tell what derived class those objects belong to from there? right now i am considering storing a char member variable which i can check (0 = CBase, 1 = CItem, 2 = CWeapon, et cetera)... or maybe a virtual function that returns the type (also more or less returning a char, but overridden in the derived classes)... then i can check this number and take appropriate action (i.e. if this object has a 2 (weapon), cast it to CWeapon and grab it''s damage stat). is there a nice function or something so i can put:

CWeapon DaWeapon;
CBase* DaItem = &DaWeapon
ClassType = FetchClass(DaItem);
 
or something to that effect?
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
Advertisement
Look into C++ RTTI ( Run-Time Type Information ).

"Doomed to crumble, unless we grow, and strengthen our communication" - Maynard James Keenan, Tool
daerid@gmail.com
quote:Original post by krez
let''s say i have a virtual base class, CThing, from which is derived CItem, CWeapon, CArmor, et cetera... some other classes are derived from these derived classes as well. i use a pointer to the base class for an inventory listing (as all the specific details aren''t important, i just want a quick listing). is there a way to tell what derived class those objects belong to from there?


Rooting a class hierarchy at something with a name like "CThing" is rarely a good idea. It bypasses the type-safety system and violates LSP.

quote:
right now i am considering storing a char member variable which i can check (0 = CBase, 1 = CItem, 2 = CWeapon, et cetera)... or maybe a virtual function that returns the type (also more or less returning a char, but overridden in the derived classes)... then i can check this number and take appropriate action (i.e. if this object has a 2 (weapon), cast it to CWeapon and grab it''s damage stat).


If you were to adhere to LSP then you would not need to do this, you would prefer to use the builtin runtime polymorphism facilities of C++. I''d recommend that you look at refactoring your design to remove the need to manually discriminate on type.

If you are hell-bent on doing this, then you need to use the dynamic_cast<> facility to perform dynamic downcast. Look it up in your favourite C++ book.
you should elaborate on what your trying to do, because it doesnt make alot of since.
you can get the type like this:
  class C{public: const type_info& getType() {return typeid(this); }};int main(int argc, char* argv[]){	C c;        cout << c.getType().name;	return 0;}  

however, imo, typeid is really, really, crappy.

generally, when you use virtual, you dont need to worry about the type since the compiler will make virtual tables.

if you are putting many unrelated derived classes in a single array (why?), what you can do is use a general accessor to get the item to do what you want, assuming that it has been initialized.
  class Cbase {public: virtual void act() = 0;};class Cweapon: public Cbase{int dmg;public: void act();};class Cdude: public Cbase{int hp;public: void act();};  

in this example, i can call act no matter how unrelated the dobob is from the other dobobs, without worry.

IF YOU THOUGHT IT OUT, then, for a base like Citem, you could have a function called effect(Cbase* object), and you wouldnt need to know the Citem type or Cbase type.
  class Citem{public: virtual int effect(Cbase* object) = 0;};class Cweapon: Citem{ int _dmg;public: int effect(Cbase* object) {  object->hp = object->hp - ( _dmg - object->ar); }};  


workable?

quote:Original post by SabreMan
Rooting a class hierarchy at something with a name like "CThing" is rarely a good idea. It bypasses the type-safety system and violates LSP.

er... i don''t get you on this one... how would the name of my class violate anything? what is LSP?
quote:If you were to adhere to LSP then you would not need to do this, you would prefer to use the builtin runtime polymorphism facilities of C++. I''d recommend that you look at refactoring your design to remove the need to manually discriminate on type.

maybe i will adhere to LSP when i find out what it is... please don''t think i''m being lazy, google told me LSP was six million different things, and Louisiana State Police was as good a match as any... but i DO need to know the type... say you can right-click on any inventory item (an array of CThings, which holds the name and icon of the item) and get a pop-up menu of what you can do with it. a potion could be drank, a weapon can be equipped, and other red herring items have no actual use. i suppose i could put all sorts of stuff into the base class (an array of menu items, et cetera) to track this, but i''d rather get it from the derived classes and then use the functions there.
but anyways, thanks for your condescension.
EvilCrap: they are not completely unrelated derived classes, they are an array of items in the inventory (all are derived one way or another from CThing). so, i can list them all as if they were just CThings, but i can also grab one and use it''s class-specific functions (the base class doesn''t have an equip() function like the weapons and armor do) by re-casting it. i don''t want to use something like the effect() method you mentioned, because some of them will have one useful function, and others might have many.
daerid: i will google that one...

--- krez (krezisback@aol.com)
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
quote:Original post by krez
er... i don''t get you on this one... how would the name of my class violate anything? what is LSP?


It''s not the name of the class, it''s what the name makes me think you are doing with it. It''s similar to CObject in MFC, and it implies a deep hierarchy with a root class containing very few semantics. What you have described you are doing is little more than using the root to give you a placeholder - it''s not really any better than casting to void*. LSP is Liskov Substitution Principle, and is a fundamental principle of OO.

quote:
maybe i will adhere to LSP when i find out what it is... please don''t think i''m being lazy, google told me LSP was six million different things, and Louisiana State Police was as good a match as any...


I assumed that you would have heard of it. I have to make some assumptions to be able to communicate with you.

quote:
but i DO need to know the type... say you can right-click on any inventory item (an array of CThings, which holds the name and icon of the item) and get a pop-up menu of what you can do with it. a potion could be drank, a weapon can be equipped, and other red herring items have no actual use. i suppose i could put all sorts of stuff into the base class (an array of menu items, et cetera) to track this, but i''d rather get it from the derived classes and then use the functions there.


How you design is up to you, I was offering some hints on things you are doing which experienced designers avoid.

quote:
but anyways, thanks for your condescension.


What is it about certain people that they come to a public forum asking for help, and they are simply unable to accept advice graciously? I have not at all been condescending. In fact, I assumed that you had more knowledge than I now think you do. It''s often difficult to judge how much someone knows from a single post, and I had to make some assumptions about what I thought you might know. So, in taking time out of my own day to try and offer help, I''ve simply discovered that you have a chip on your shoulder.

You might also like to consider that I actually gave you the answer to your immediate question, but you seem to have ignored that simple fact.

--

It is against the law to stare at the mayor of Paris.
quote:Original post by SabreMan
It''s not the name of the class, it''s what the name makes me think you are doing with it. It''s similar to CObject in MFC, and it implies a deep hierarchy with a root class containing very few semantics. What you have described you are doing is little more than using the root to give you a placeholder - it''s not really any better than casting to void*. LSP is Liskov Substitution Principle, and is a fundamental principle of OO.

ah... ok then. the base class holds information that is common to all the derived classes, and a few virtual functions that are overridden when necessary. what principle is it that makes this just as bad as using void*? having looked up LSP (thanks for the full spelling), i don''t see how i have violated it (of course, i only just read about it whereas you have been studying it for years).
quote:What is it about certain people that they come to a public forum asking for help, and they are simply unable to accept advice graciously? I have not at all been condescending.

except for:
quote:I assumed that you would have heard of it. I have to make some assumptions to be able to communicate with you.

quote:How you design is up to you, I was offering some hints on things you are doing which experienced designers avoid.

quote:In fact, I assumed that you had more knowledge than I now think you do.

my apologies for seeming ungracious... i do tend to get snippy when i ask a specific question and someone takes it upon themselves to degrade my design rather than just answering. but, since the subject has been brought up, how exactly would you implement the system i was talking about (storing an array of pointers to a base class, and being able to pick one and call a specific function in it)?
quote:You might also like to consider that I actually gave you the answer to your immediate question, but you seem to have ignored that simple fact.

if you consider "you are doing it all wrong, but if you are hell-bent... look it up in your favorite c++ book" an answer.
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
I don''t know if this would work but couldn''t you make a string that could tell what type it is? If you are making a weapon set that string to WEAPON. Then when you want to see what type it is just make a function that retrieves it. Thats what I would try.

Jeff D
Suffered seven plagues, but refused to let the slaves go free. ~ Ross Atherton
#include <iostream>#include <typeinfo>using namespace std;class Base{public: //code...};class Derived : class Base{public: //code...};class Derived2 : class Base{public://code};int main(){Base *p,b;Derived d;p = &Derived   .   . p = &Derived2  .  .cout << "the type of object p is pointing to " << typeid(*p).name() << "\n";return 0;}  



-----------------------------
"There are ones that say they can and there are those who actually do."

"...u can not learn programming in a class, you have to learn it on your own."



Edited by - cMADsc on February 25, 2002 5:58:31 PM
-----------------------------"There are ones that say they can and there are those who actually do.""...u can not learn programming in a class, you have to learn it on your own."
storing the items as the baseclass is your problem. there is no good way to overcome your problem without really defeating the purpose of an object-oriented design. you need to design your base class so that all derived classes have the same interface (variables and functions). and yes some of that info may not be relevant on all classes, but that''s a much easier problem to solve than the one you''re facing right now. that''s how i would do it anyway.

This topic is closed to new replies.

Advertisement