views:

204

answers:

7

The below code explains the problem. Fill in same_sub_class to detect if the two pointers to virtual base class A are in fact the same concrete class.

struct A {
    ...
}:

struct B : public A {
    ...
}:

struct C : public A {
    ...
}


bool same_sub_class(A * a1, A * a2){
    // Fill this in to return true if a1 and a2 are
    // of the same concrete class
}

EDIT:

As I look at my application I need something slightly different from the above. I need to be able to group instances by their type_id.

FYI. I have a mini symbolic algerbra system so to do manipulations it is important to know the class type sometimes for sorting, and rearranging expressions.

So given a vector of pointers to instance how to group them by their type_id. I'd either need to be able to hash the type_id or generate a unique integer for every class.

+13  A: 

If you can use RTTI,

typeid(*a1) == typeid(*a2)

I think you also need to

#include <typeinfo>

And you must have a virtual function in your classes so that the vtable exists--a destructor should do fine.

UPDATE:

I'm not sure I completely understand what your requirements are for grouping (Do you need some kind of deterministic ordering? What should happen with sub-subclasses?), but you could try using the value returned from the typeid operator to either:

  • Hash the string returned from typeid(*ptr).name()
  • Use typeid(*a1).before(typeid(*a2)) as an ordering criterion. This doesn't have any determinism between runs, though.

Generally when considering RTTI, it is a good idea to see if any of this can be accomplished better using well-crafted virtual functions (double dispatch, for example). I really can't say if there is a good alternative in your case though, since I don't understand the specifics.

Tim Yates
You need to remember to include `<typeinfo>` as well.
Charles Bailey
But `A` has to be polymorphic isn't??
liaK
@liaK, yes, the base class must have at least one virtual function.
avakar
@avakar, fine.. thanx.. :)
liaK
@Tim thanks for that. I've made an edit to the question to better reflect the problem I'm trying to solve. Turns out that simple equality is not quite what I need.
bradgonesurfing
nice answer...........
Nishant
@bradgonesurfing Check out my update. I'm not sure if I get it.
Tim Yates
"Hash the string returned from typeid(*ptr).name()" - Ouch! Let's see: OP has to have at least one virtual function anyway, for `typeid` to work. Isn't adding a virtual function that returns type_id as simple `int` the easiest way?
Maciej Hehl
@Maciej Hehl, I think that would be the best. I was just trying to update my answer without changing it completely. It's really a completely different question though.
Tim Yates
make a protected 'typeTag' member initialized in constructor of subclasses, like i suggested below. Then you can hash or group your instances on that member.
Adesit
+4  A: 
typeid(*a1) == typeid(*a2)

Note the dereference, it is important.

usta
Yeah, I just noticed that. Thanks for pointing that out (pun intended?).
Tim Yates
You're welcome. No pun intended, I just wanted to make it clear.
usta
By the way, your answer now looks great, an up vote from me ;)
usta
Mutually, of course.
Tim Yates
A: 

Isn't this platform specific ? And what about polymorphism?

crg
No, it isn't, RTTI is part of the standard. BTW, such kind of question should go in comments, not as an aswer.
Matteo Italia
@Matteo :- I think you can't add comments until you gain some amount of reputation score. I had also face the same thing.
Manoj R
Uh, yes, I forgot about that. :)
Matteo Italia
+2  A: 

You could make your own type Identifier:

struct A{
...
protected:
 enum TypeTag{B_TYPE, C_TYPE};
 TypeTag typeTag;
};

And then in constructors of subclasses:

B::B()
: typeTag(TypeTag::B_TYPE)
{
...
}

C::C()
: typeTag(TypeTag::C_TYPE)
{
...
}
Adesit
nice explanation..........
Nishant
typeTag better be private. Not enum but variable.
Manoj R
@Manoj: i disagree. typeTag is initialized in the sublasses constructor, so it can't be private member of base class.
Adesit
@Adesit: typeTag must be protected. But this mechanism is not perfect, because on adding new descendant we need to add new member of enum. Best regards to Odessa :)
zabulus
I think it's a bad idea, better to use RTTI
piotr
@piotr Its not fair to simply say "this bad" unless you provide a reason. I dont know it for sure, but i think my idea is kind of what rtti is inside. Generally speaking, most of the time its good to stick to the standard, but sometimes its better to implement something yourself. We dont know the exact circumstances of the poster. Consider for example, that rtti is not supported under Android NDK.
Adesit
http://groups.google.com/group/android-ndk/browse_thread/thread/5804b3442bb394b1?pli=1
piotr
interesting link: somebody built a customized version of NDK which in fact does support RTTI. Thats fine. But note, thats not original google's NDK.
Adesit
A: 

There is a feature in C++ called RTTI (runtime type information) which allows you to do such things.

One other possibility to have runtime type checking is to create a base class from which all your classes derive from. In your base class include a field which contains its type as a string or a number.

codymanix
RTTI is standard C++.
Sjoerd
sorry that I was wrong, I corrected this.
codymanix
A: 

One trick that may or may not work with RTTI, depending on your compiler, is the following

const type_info &a1_type_info= typeid(*a1);
const type_info &a2_type_info= typeid(*a2);

return &a1_type_info==&a2_type_info || a1_type_info==a2_type_info;

If your compiler creates type_info instances by value, this will fail the first test but succeed on the second test. If your compiler caches the instances, the first test will succeed (if it's the same type) and be much faster since it's just a pointer compare. If your compiler returns different instances because a1 and a2 came from different shared libraries, it should still work.

MSN
+1  A: 

Actually there are a fairly simple answers to this. But it involves posing the questions a bit clearer.

(A) If I want to store typeinfo objects in an unordered_set what do I need to do?

typeinfo support the == and the name() method. The name can be used to generate a hash and == for equality

(B) If I want to store typeinfo objects in an ordered_set ( std::set ) what do I need to do?

typeinfo supports the == and the before() method. With bit of wrapping of these two methods I can implement an interface for a Compare function that gives me strict weak ordering.

bradgonesurfing