[mrpt-rtti]

Runtime Type Information (RTTI) library, providing compiler-independent class registry, class factory, and inheritance information.

Library mrpt-rtti

This library is part of MRPT and can be installed in Debian-based systems with:

sudo apt install libmrpt-rtti-dev

Read also how to import MRPT into your CMake scripts.

Any class with RTTI support has to be derived from mrpt::rtti::CObject, either directly or via a hierarchy of inheriting classes. Class factory by name enables deserialization of polymorphic classes in the library [mrpt-serialization].

All classes defined in each MRPT module are automatically registered when loading the module (if dynamically linked).

Example #1: defining new user classes

See: rtti_example1/test.cpp

#include <mrpt/rtti/CObject.h>

#include <iostream>
#include <memory>

namespace MyNS
{
class Foo : public mrpt::rtti::CObject
{
   public:
    Foo() {}
    DEFINE_MRPT_OBJECT(Foo, MyNS)

    void printName() { std::cout << "printName: Foo" << std::endl; }
};

class BarBase : public mrpt::rtti::CObject
{
   public:
    BarBase() {}
    DEFINE_VIRTUAL_MRPT_OBJECT(BarBase)

    virtual void printName() { std::cout << "printName: BarBase" << std::endl; }
};

class Bar : public BarBase
{
   public:
    Bar() {}
    DEFINE_MRPT_OBJECT(Bar, MyNS)

    void printName() override { std::cout << "class: Bar" << std::endl; }
    void specificBarMethod()
    {
        std::cout << "specificBarMethod: reached." << std::endl;
    }
};
}  // namespace MyNS

IMPLEMENTS_MRPT_OBJECT(Foo, mrpt::rtti::CObject, MyNS)
IMPLEMENTS_VIRTUAL_MRPT_OBJECT(BarBase, mrpt::rtti::CObject, MyNS)
IMPLEMENTS_MRPT_OBJECT(Bar, MyNS::BarBase, MyNS)
void Test_UserTypes()
{
    using namespace MyNS;
    const auto id_foo = CLASS_ID(Foo);
    std::cout << "RTTI Foo (static): " << id_foo->className << std::endl;

    // Pointers:
    Bar::Ptr pBar = std::make_shared<Bar>();
    BarBase::Ptr pBase = mrpt::ptr_cast<BarBase>::from(pBar);
    mrpt::rtti::CObject::Ptr pObj =
        mrpt::ptr_cast<mrpt::rtti::CObject>::from(pBar);

    pBar->printName();
    pBase->printName();
    std::cout << "Is Foo?   => " << (IS_DERIVED(*pObj, Foo) ? "Yes\n" : "No\n");
    std::cout << "Is BarBase? => "
              << (IS_DERIVED(*pObj, BarBase) ? "Yes\n" : "No\n");
    std::cout << "Is Bar?  => " << (IS_DERIVED(*pObj, Bar) ? "Yes\n" : "No\n");
    if (IS_CLASS(*pObj, Bar))
    {
        auto pBar2 = mrpt::ptr_cast<Bar>::from(pObj);
        pBar2->specificBarMethod();
    }
}

Output:

RTTI Foo (static): Foo
class: Bar
class: Bar
Is Foo?     => No
Is BarBase? => Yes
Is Bar?     => Yes
specificBarMethod: reached.

Example #2: using the class factory

See: rtti_example1/test.cpp

#include <mrpt/rtti/CObject.h>

#include <iostream>
#include <memory>

namespace MyNS
{
class Foo : public mrpt::rtti::CObject
{
   public:
    Foo() {}
    DEFINE_MRPT_OBJECT(Foo, MyNS)

    void printName() { std::cout << "printName: Foo" << std::endl; }
};

class BarBase : public mrpt::rtti::CObject
{
   public:
    BarBase() {}
    DEFINE_VIRTUAL_MRPT_OBJECT(BarBase)

    virtual void printName() { std::cout << "printName: BarBase" << std::endl; }
};

class Bar : public BarBase
{
   public:
    Bar() {}
    DEFINE_MRPT_OBJECT(Bar, MyNS)

    void printName() override { std::cout << "class: Bar" << std::endl; }
    void specificBarMethod()
    {
        std::cout << "specificBarMethod: reached." << std::endl;
    }
};
}  // namespace MyNS

IMPLEMENTS_MRPT_OBJECT(Foo, mrpt::rtti::CObject, MyNS)
IMPLEMENTS_VIRTUAL_MRPT_OBJECT(BarBase, mrpt::rtti::CObject, MyNS)
IMPLEMENTS_MRPT_OBJECT(Bar, MyNS::BarBase, MyNS)
void do_register()
{
    // Register with explicit namespace:
    mrpt::rtti::registerClass(CLASS_ID_NAMESPACE(Foo, MyNS));
    {
        // Register without explicit namespace:
        using namespace MyNS;
        mrpt::rtti::registerClass(CLASS_ID(BarBase));
        mrpt::rtti::registerClass(CLASS_ID(Bar));
        mrpt::rtti::registerClassCustomName("MyNS::Bar", CLASS_ID(Bar));
    }
}

void Test_UserTypesFactory()
{
    do_register();

    // Test register:
    {
        const auto& allClasses = mrpt::rtti::getAllRegisteredClasses();
        for (const auto& cl : allClasses)
        {
            std::cout << "Known class: " << cl->className << ", children of "
                      << (cl->getBaseClass ? cl->getBaseClass()->className
                                           : "(none)")
                      << std::endl;
        }
    }

    // Test factory:
    {
        mrpt::rtti::CObject::Ptr pObj = mrpt::rtti::classFactory("MyNS::Bar");
        if (IS_CLASS(*pObj, MyNS::Bar))
        {
            auto pBar = mrpt::ptr_cast<MyNS::Bar>::from(pObj);
            pBar->specificBarMethod();
        }
    }
}

Output:

Known class: Bar, children of BarBase
Known class: BarBase, children of CObject
Known class: CObject, children of (none)
Known class: Foo, children of CObject
Known class: Bar, children of BarBase
specificBarMethod: reached.

Library contents

// structs

struct mrpt::rtti::TRuntimeClassId;

template <typename CAST_TO>
struct mrpt::ptr_cast;

// classes

class mrpt::rtti::CListOfClasses;
class mrpt::rtti::CObject;

// global functions

void mrpt::rtti::registerAllClasses_mrpt_rtti();

Global Functions

void mrpt::rtti::registerAllClasses_mrpt_rtti()

Forces manual RTTI registration of all serializable classes in this namespace.

Should never be required to be explicitly called by users, except if building MRPT as a static library.