Click here to Skip to main content
13,732,045 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

16.5K views
269 downloads
11 bookmarked
Posted 12 Apr 2016
Licenced CPOL

C++: Custom RTTI

, 12 Apr 2016
Rate this:
Please Sign up or sign in to vote.
This tip presents a custom RTTI class which is 10x faster than dynamic_cast

This tip presents a intrusive custom RTTI class which provides better performance than dynamic_cast. This class is found in the Real-Time 3D Rendering with DirectX and HLSL by Paul Varcholik. Benchmark shows 10x performance lead over dynamic_cast. For those who may not be familiar, dynamic_cast is used in C++ to do downcast to derived class. For upcast to base class generally do not need any explicit casting. Runtime Type Information (RTTI) must be enabled in the compiler to use dynamic_cast.

Benchmark under VC2010 Windows
     DynamicCast: 1266ms
          AsCast:  127ms

Below shows the entire RTTI class which other class needs to be inherited from. User has to define RTTI_DECLARATIONS macro inside their class.

#pragma once

#include <string>

namespace Library
{
    class RTTI
    {
    public:
        virtual const size_t TypeIdInstance() const = 0;
        
        virtual RTTI* QueryInterface(const size_t)
        {
            return nullptr;
        }
        virtual const RTTI* QueryInterface(const size_t) const
        {
            return nullptr;
        }

        virtual bool Is(const size_t id) const
        {
            return false;
        }

        virtual bool Is(const std::string& name) const
        {
            return false;
        }

        template <typename T>
        T* As() 
        {
            if (Is(T::TypeIdClass()))
            {
                return (T*)this;
            }

            return nullptr;
        }
        template <typename T>
        const T* As() const
        {
            if (Is(T::TypeIdClass()))
            {
                return (T*)this;
            }

            return nullptr;
        }
    };

#define RTTI_DECLARATIONS(Type, ParentType)                            \
    public:                                                            \
        static std::string TypeName() { return std::string(#Type); }   \
        virtual const size_t TypeIdInstance() const                    \
        { return Type::TypeIdClass(); }                                \
        static const size_t TypeIdClass()                              \
        { static int d = 0; return (size_t) &d; }                      \
        virtual Library::RTTI* QueryInterface( const size_t id )       \
        {                                                              \
            if (id == TypeIdClass())                                   \
                { return (RTTI*)this; }                                \
            else                                                       \
                { return ParentType::QueryInterface(id); }             \
        }                                                              \
        virtual const Library::RTTI* QueryInterface( const size_t id ) const \
        {                                                              \
            if (id == TypeIdClass())                                   \
                { return (RTTI*)this; }                                \
            else                                                       \
                { return ParentType::QueryInterface(id); }             \
        }                                                              \
        virtual bool Is(const size_t id) const                         \
        {                                                              \
            if (id == TypeIdClass())                                   \
                { return true; }                                       \
            else                                                       \
                { return ParentType::Is(id); }                         \
        }                                                              \
        virtual bool Is(const std::string& name) const                 \
        {                                                              \
            if (name == TypeName())                                    \
                { return true; }                                       \
            else                                                       \
                { return ParentType::Is(name); }                       \
        }                                                              
}

The trick to uniquely identify a class is by using address of a local static member which should be unique. Credit: Andrew Fedoniouk aka c-smile.

static const size_t TypeIdClass()
{ static int d = 0; return (size_t) &d; }

The usage difference between dynamic_cast and As() member is shown below

Parallelogram* p = dynamic_cast<Parallelogram*>(vec[i]);

Parallelogram* p = vec[i]->As<Parallelogram>();

As the reader may notice As() function do C style cast instead of reinterpret_cast. The compiler will complain of using reinterpret_cast in a const member function.

template <typename T>
const T* As() const
{
    if (Is(T::TypeIdClass()))
    {
        return (T*)this;
    }

    return nullptr;
}

For those who want to use this class in C++98, just change nullptr to NULL. Note: this class does not work in multiple inheritance if more than 1 base class derive from it. Source code is hosted at Github.

History

  • 2015-12-31: Initial release
  • 2016-01-02: Replaced sRunTimeTypeId with a static local variable, so the class is "header only" and Makefile is fixed.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Shao Voon Wong
Software Developer (Senior)
Singapore Singapore
Right now, I am picking up DevOps skills at Pluralsight and pursuing CCNA certification. Stay tuned for my CCNA related article!

Coding Tidbit Blog

Latest blogpost: C++ – The Forgotten Trojan Horse by Eric Johnson

IT Certifications

  • IT Infrastructure Library Foundational (ITIL v3)
  • Scrum Alliance Certified Scrum Master (CSM)
  • Certified Secure Software Lifecycle Professional (CSSLP)

View my certificates here.

You may also be interested in...

Comments and Discussions

 
QuestionRTTI_DEFINITIONS(Type) is redundant Pin
c-smile1-Jan-16 18:58
memberc-smile1-Jan-16 18:58 
AnswerRe: RTTI_DEFINITIONS(Type) is redundant Pin
Shao Voon Wong1-Jan-16 19:32
professionalShao Voon Wong1-Jan-16 19:32 
GeneralRe: RTTI_DEFINITIONS(Type) is redundant Pin
Shao Voon Wong3-Jan-16 2:50
professionalShao Voon Wong3-Jan-16 2:50 
QuestionConstness does not seems to be respected Pin
Philippe Mori31-Dec-15 6:33
memberPhilippe Mori31-Dec-15 6:33 
AnswerRe: Constness does not seems to be respected Pin
Shao Voon Wong1-Jan-16 17:21
professionalShao Voon Wong1-Jan-16 17:21 
GeneralRe: Constness does not seems to be respected Pin
Philippe Mori2-Jan-16 4:07
memberPhilippe Mori2-Jan-16 4:07 
Suggestionnote for multiple inheritance Pin
D4rkTrick4-Jan-16 10:13
professionalD4rkTrick4-Jan-16 10:13 
GeneralRe: note for multiple inheritance Pin
Shao Voon Wong4-Jan-16 17:47
professionalShao Voon Wong4-Jan-16 17:47 
GeneralRe: Constness does not seems to be respected Pin
William E. Kempf4-Jan-16 10:43
memberWilliam E. Kempf4-Jan-16 10:43 
GeneralRe: Constness does not seems to be respected Pin
Shao Voon Wong4-Jan-16 13:43
professionalShao Voon Wong4-Jan-16 13:43 
GeneralRe: Constness does not seems to be respected Pin
William E. Kempf5-Jan-16 2:35
memberWilliam E. Kempf5-Jan-16 2:35 
GeneralRe: Constness does not seems to be respected Pin
Stefan_Lang22-Apr-16 5:40
memberStefan_Lang22-Apr-16 5:40 
GeneralRe: Constness does not seems to be respected Pin
Shao Voon Wong22-Apr-16 15:25
professionalShao Voon Wong22-Apr-16 15:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180920.1 | Last Updated 12 Apr 2016
Article Copyright 2016 by Cake Processor
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid