[mrpt-rtti]

Overview

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.