12

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.

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217

6 Answers6

22

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
  • 5,151
  • 2
  • 29
  • 29
  • 1
    You need to remember to include `` as well. – CB Bailey Oct 05 '10 at 12:33
  • But `A` has to be polymorphic isn't?? – liaK Oct 05 '10 at 12:39
  • 2
    @liaK, yes, the base class must have at least one virtual function. – avakar Oct 05 '10 at 12:40
  • @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 Oct 05 '10 at 12:51
  • @bradgonesurfing Check out my update. I'm not sure if I get it. – Tim Yates Oct 05 '10 at 15:28
  • 1
    "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 Oct 05 '10 at 16:49
  • @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 Oct 05 '10 at 21:50
  • 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 Oct 06 '10 at 11:51
10
typeid(*a1) == typeid(*a2)

Note the dereference, it is important.

usta
  • 6,699
  • 3
  • 22
  • 39
2

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
  • 159
  • 5
  • typeTag better be private. Not enum but variable. – Manoj R Oct 05 '10 at 12:56
  • @Manoj: i disagree. typeTag is initialized in the sublasses constructor, so it can't be private member of base class. – Adesit Oct 05 '10 at 13:14
  • @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 Oct 05 '10 at 13:59
  • I think it's a bad idea, better to use RTTI – piotr Oct 05 '10 at 14:33
  • @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 Oct 06 '10 at 11:42
  • http://groups.google.com/group/android-ndk/browse_thread/thread/5804b3442bb394b1?pli=1 – piotr Oct 07 '10 at 15:47
  • 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 Oct 07 '10 at 16:15
2

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
  • 30,949
  • 17
  • 114
  • 217
1

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
  • 28,510
  • 21
  • 92
  • 151
0

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
  • 53,214
  • 7
  • 75
  • 105