5

is there any advantage of using your own type identifier over RTTI?

e.g.

class A { virtual int mytype() = 0; };
class B : public A { int mytype() {return 1;} };
class C : public A { int mytype() {return 2;} };

Could it be faster? Less overhead? Or should one always use RTTI in such a situation?

Cookie
  • 12,004
  • 13
  • 54
  • 83
  • 8
    Why take on the job, which the compiler does for you for free ? Any gains, if achieved, isn't worth it. – DumbCoder May 25 '11 at 12:45
  • You might be interested in reading LLVM's implementation of such a system: http://stackoverflow.com/questions/6038330/how-is-llvm-isa-implemented/6068950 Do bear in mind that it is heavy, and they only implemented it to be able to deactive RTTI. – Matthieu M. May 25 '11 at 13:06
  • Well, my question is precisely around what gains would be achieved. I guess I am just a bit unaware of how those two solutions will differ in implementation. – Cookie May 25 '11 at 13:13
  • 1
    RTTI generates information for every object with virtual methods, without a priori knowledge of whether this information will be necessary or not. It's unfortunately a direct violation of the "you don't pay for what you don't use" mindset. Also, RTTI has to cater for awkward cases (multi-inheritance and virtual inheritance) making the implementation (and thus the cost) non-trivial. LLVM's system thus not only saves some memory, but also some computations. It puts the onus on the developer though, which means bugs are more likely... – Matthieu M. May 25 '11 at 14:42

3 Answers3

6

Don't assume that RTTI will have more/less overhead than your solution before testing it.

You should try both solutions and measure the performances to get a reliable answer.

I actually asked myself the same question a few years ago and I ended up adding a member variable to "fasten" the type testing, just like you did. Turned out my code was needlessly cluttered with stupid tests while some dynamic_cast<> would have done the same job (in fact, a better job).

I refactored the code to use dynamic_cast<> since then and I wouldn't go back.

As a foot-note: if your classes are polymorphic, you already "paid" for this anyway, so just go with dynamic_cast<>.

ereOn
  • 53,676
  • 39
  • 161
  • 238
  • Hmm. Usually I use above information in case switch statements, or using RTTI in if else if else ... constructs. Are you suggesting to try a dynamic cast to sth, see if it fails, then dynamic cast again, ... until successfull? Isn't typeid (e.g. RTTI) better suited there? Mostly I am using this in factory design btw. – Cookie May 25 '11 at 13:10
  • @Cookie: I don't know much about your current design so I can't answer reliably. But as a general rule, a good design doesn't require that much type testing. Why do you need to know the type of your instances ? Can't you just call its methods transparently ? If not, are you sure that inheritance is what you really need ? – ereOn May 25 '11 at 13:12
  • Well, one case is a general message queue between two threads that holds generic pointers of type Msg. All subclasses derive from Msg. The reader thread then needs to figure out what to do with each msg based on the type of msg. What the reader does with a msg doesn't really belong to the msg because every reader might do sth different. Hence you end up with a switch statement in the reader. – Cookie May 25 '11 at 13:19
  • 1
    @Cookie: I see. The thing is: inheritance should be chosen not because of technical choices (like having the ability to store different instance types into the same list) but because it makes sense (a `Car` derives from a `Vehicle` because a car **is** a vehicle). What prevents you to have several lists for differents message types to avoid the useless testing ? The problem is: when you add a specific instance to a generic list, you somehow **loose** information and this loss has a cost: you have to test types when it comes to getting the messages back. – ereOn May 25 '11 at 13:28
  • The need to maintain order. And after all, different types of messages are still messages (they might e.g. all have a timestamp). But I do see what you are trying to say. – Cookie May 25 '11 at 13:52
  • @Cookie: You might also consider a different approach, similar to what Boost ASIO or Qt does: having something like signal and slots (or the ability to "post" messages to a thread queue directly) usually makes the design much better without the cost of having to maintain different message lists. – ereOn May 25 '11 at 13:58
  • @Cookie: have you considered a *Visitor* pattern ? What you are trying to achieve is generally handled through multi-methods, and the Visitor pattern is the de-facto pattern to implement this in languages that lack them. – Matthieu M. May 25 '11 at 14:38
5

The disadvantages (for polymorphic types) with custom type identifier are:

  1. One needs to keep record of every class inherited. You need to assign a unique integer or enum value for all the classes in a given hierarchy
  2. Say your vertical inheritance is like, A->B->D. For situations like, A *p = new D; the custom type identification will not allow to match B* with p (even though it's valid).

You need to be aware of these situations. On the other had,

  1. RTTI is applicable to only polymorphic types (so the inheritance chain not containing virtual functions cannot leverage RTTI)
  2. There is a little performance difference decrease due to RTTI, if it really matters to you

But, as you mentioned in your comment, for smaller inheritance chain, there is no harm in keeping track of your own typing. e.g.

struct Base {
  enum TYPES { _BASE, _D1, _D2, _D3 };
  const TYPES &myType;
  Base (TYPES) : myType(_BASE) {}
};

struct D1 : Base {
  D1 () : Base(_D1) {}
};
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    the second point can be circumvented, you may which to check how LLVM has implemented it. – Matthieu M. May 25 '11 at 13:04
  • True true, I am aware of drawbacks of not using RTTI, I am just wondering whether there are drawbacks of using RTTI. I guess if RTTI keeps track of the whole inheritance chain, that might be an overhead? But what if the chain is only one long? – Cookie May 25 '11 at 13:12
  • @Cookie, I have edited my answer. For smaller chains, IMHO there is no harm to have custom types. – iammilind May 25 '11 at 13:21
3

http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI

There are some limitations to RTTI. First, RTTI can only be used with polymorphic types. That means that your classes must have at least one virtual function, either directly or through inheritance. Second, because of the additional information required to store types some compilers require a special switch to enable RTTI.

So, if you need it to work on classes without virtual functions, you'd have to implement it yourself.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • 3
    True, but the OPs suggested 'homebrew RTTI' uses a virtual function anyway. – Roddy May 25 '11 at 12:54
  • I also don't really see how that could be the case, unless one doesn't inherit. Inheritance automatically introduces a virtual destructor, doesn't it? – Cookie May 25 '11 at 13:06
  • 1
    @Cookie: that's not true: inheritance != polymorphism. One can use inheritance **without** needing a virtual destructor. Actually, that's even a common case. (Note that in C++, you also have private inheritance which cannot be used for polymorphism) A virtual destructor is usually only needed when dealing with polymorphism. – ereOn May 25 '11 at 13:14