RTTI

RTTI (Run-Time Type Information, tj. informace o typu za běhu) nebo Run-Time Type Identification (tj. typová identifikace za běhu) je v informatice technika používaná v programovacím jazyce C++, která odhaluje informaci o datovém typu objektu za běhu programu. RTTI může být aplikována jak na jednoduché datové typy (např. celá čísla, znaky), tak také na generické datové typy. Tato technika je specializací jazyka C++, která rozšiřuje obecný koncept techniky nazývané typová introspekce. Podobné techniky jsou ovšem známé i z jiných programovacích jazyků, jako je například Delphi (Object Pascal).

Zajímavostí pak je, že v původní implementaci jazyka C++ tato technika nebyla vložena, jelikož se její autor Bjarne Stroustrup domníval, že by byl mechanismus velmi často používán špatným způsobem.[1]

Vlastnosti

Základními částmi RTTI v C++ jsou operátor přetypování dynamic_cast<> a operátor typeid.

Tyto funkce pro zjištění datového typu za běhu programu umožňují bezpečnější přetypování či jinou manipulaci s datovými typy.

RTTI je dostupná pouze pro polymorfní třídy, což znamená, že třída musí mít nejméně jednu virtuální metodu. V praxi tato podmínka ovšem nepředstavuje žádný problém, jelikož základní třídy musí mít virtuální destruktor, tak aby objekty odvozených tříd mohly provést řádné vyčištění paměti, pokud jsou mazány pomocí ukazatele na základní datový typ.

RTTI je v některých kompilátorech pouze volitelnou součástí, programátor si tak může během procesu kompilace zvolit, jestli funkce bude nebo nebude obsažena. To může také způsobit zvýšení nároků na zdroje, v případě že je technika RTTI vložena ale není používána.

Ukázka v jazyce C++

//Ukazatel na objekt třídy předka může odkazovat na objekt libovolné třídy, která 
//je z něj poděděna. RTTI lze použít ke zjištění jakého typu (některá ze tříd 
//dědící z předka) je objekt, na který je odkazováno ukazatelem předka.

#include <iostream>
//Pro použití operátoru typeid je nutno připojit knihovnu typeinfo
#include <typeinfo>

class Predek
{
public:
    virtual ~Predek()
    {
    } 
};
class Potomek: public Predek
{
};

int main()
{
    Predek* potomek1 = new Potomek();
    Potomek* potomek2 = nullptr;

    //Použití operátoru typeid
    const std::type_info& info=typeid(*potomek1);
    if(info == typeid(Potomek))
    {
        std::cout<<"Ukazatel potomek1 ukazuje na objekt třídy Potomek\n";
    }
    else
    {
        std::cout<<"Ukazatel potomek1 ukazuje na objekt třídy Predek\n";
    }
    try
    {
        //Tohle není nedefinované chování-vyhodí to výjimku std::bad_typeid
        typeid(*potomek2);//potomek2 je nulový ukazatel
    }
    catch(std::bad_typeid err)
    {
    }
    //Použití operátoru přetypování dynamic_cast
    potomek2 = dynamic_cast<Potomek*>(potomek1);
    if (potomek2 != nullptr)
    {
        std::cout<<"Ukazatel potomek1 ukazuje na objekt třídy Potomek\n";
    }
    else
    {
        std::cout<<"Ukazatel potomek1 ukazuje na objekt třídy Predek\n";
    }

    //Potřebný virtuální destruktor 
    delete potomek1;
    delete predek;

    return 0;
}

Příklad ve kterém je RTTI použito k porovnání:

class Predek
{
public:  
    virtual ~Predek(){}
};

class Potomek : public Predek
{
public:
    Potomek() {}
    virtual ~Potomek() {}

    int porovnej (Potomek& ref);
};

int mojePorovnavaciMetodaSlouziciKSerazovani (Predek& ref1, Predek& ref2)
{
    Potomek& p = dynamic_cast<Potomek&>(ref1); //užití RTTI
    //Poznámka: Pokud se přetypování nepovede, RTTI umožňuje procesu vyhodit výjimku bad_cast exception

    return p.porovnej (dynamic_cast<Potomek&>(ref2));
}

Reference

  1. Bjarne Stroustrup. A History of C++: 1979—1991 [online]. [cit. 2009-05-18]. S. 50. Dostupné online. 

V tomto článku byl použit překlad textu z článku Run-time type information na anglické Wikipedii.