rtti
static &dynamic type information
class Base {
public:
virtual ~Base();
virtual void name();
};
class Derived1 : public Base;
class Derived2 : public Base;
Base* pd1 = new Derived1;
Base* pd2 = new Derived2;
// static type Base
// dynamic type DerivedX
dynamic_cast
rtti
static type (compile time)
decltype
auto
dynamic type (runtime)
dynamic dispatch
using t = decltype(pd1); // Base*
auto p2 = pd1; // Base*
Base* p = new Base();
// no indication of error
static_cast<Derived1*>(b);
pd1()->name(); // Derived1::name
Base* bp = new Base();
dynamic_cast<Derived1*>(b); // nulp
assert(
typeid(*pd1) == typeid(*pd2)
) // fail
static
dynamic
static_cast
typeid
#include <typeinfo> typeid(whatever) -> const std::type_info&
typeid(type)
typeid(expr_of_polymorphic_t)
typeid(expr_of_non_polym_t)
typeid(size_t)
typeid(std::string("Hello"))
auto p = new PolymorphicT;
typeid(*p);
Compile time
Compile time
Runtime
typeid(*p)
PolymorphicT p{}; // 0 initialized
typeid(*p); // std::bad_typeid
where p == nullptr
Runtime
throw std::bad_typeid
no UB
- of static storage duration
- theoretically subsequent invocations on the same type could return different objects
std::type_info
namespace std {
class type_info {
type_info() = delete;
type_info(type_info) = delete;
type_info& operator=(type_info) = delete;
virtual ~type_info();
bool operator==(const type_info& rhs) const noexcept;
// (operator!= synthesized since C++20)
bool before(const type_info& rhs) const noexcept;
std::size_t hash_code() const noexcept;
const char* name() const noexcept;
};
}
std::type_info
namespace std {
class type_info {
type_info() = delete;
type_info(type_info) = delete;
type_info& operator=(type_info) = delete;
virtual ~type_info();
bool operator==(const type_info& rhs) const noexcept;
// (operator!= synthesized since C++20)
bool before(const type_info& rhs) const noexcept;
std::size_t hash_code() const noexcept;
const char* name() const noexcept;
};
}
void use(Base* p) {
auto&& type = typeid(*p);
if (type == typeid(Derived1)) {
special_logic1();
}
else if (type == typeid(Derived2)) {
special_logic2();
}
...
}
std::unordered_map<std::type_index, std::string> m;
m[typeid(double)] = "Doubles are red";
m[typeid(32LL)] = "Long longs are blue";
m[typeid(std::string)] = "And this is cool";
for (auto&& [idx, msg] : m) {
std::cout << idx.name() << ": " << msg << '\n';
}
std::type_info
std::unordered_map<std::type_index, std::string> m;
m[typeid(double)] = "Doubles are red";
m[typeid(32LL)] = "Long longs are blue";
m[typeid(std::string)] = "And this is cool";
for (auto&& [idx, msg] : m) {
std::cout << idx.name() << ": " << msg << '\n';
}
#include <typeinfo>
#include <typeindex>
std::type_index(typeid(whatevah));
returns mangled name
getting names of types
types
std::type_info::name()
mangled name
readable name
typeid(std::string).name()
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
example under g++
getting names of types
types
getting names of types
types
constexpr auto name = typeid(int).name();
into the detailverse
D1*
B1*
...
...
VFTablePtr
struct B1 {
...
virtual void foo() {}
};
struct D1 : B1 { ... };
struct B2 {
...
virtual void bar() {}
}
struct D2 : D1, B2 { ... }
...
...
D2*
B2*
VFTablePtr
top_offset = 0
typeinfo for D2
B1::foo
top_offset = -8
typeinfo for D2
B2::bar
D1
B1
D2
B2
...
...
mangled_name
typeinfo for D2
vtable for d2
d2
example under g++
Performance
Performance
Performance
Performance
under libstdc++ (g++) and libc++ (Clang)
Performance
Performance
Performance
Performance
std::type_info::operator==
std::type_info::hash_code
std::type_info::name
or
under libstdc++ (g++) and libc++ (Clang)
!defined(_LIBCPP_NONUNIQUE_RTTI_BIT)
__GXX_MERGED_TYPEINFO_NAMES == 0
libstdc++
otherwise
default
otherwise
libc++
default
non standard compliant
disabling rtti
-fno-rtti
/GR-
under G++, Clang and similar
under MSVC
inheritance and exceptions
class my_custom_error : public std::runtime_error {
private:
std::string message;
public:
my_custom_error(std::string msg) :
message{std::move(msg)}
{
}
my_custom_error& operator=(const my_custom_error& other)
{
message = other.message;
}
const char* what() noexcept {
return message.c_str();
}
};
try {
throw my_custom_error("woah!");
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
more than inheritance
std::variant<T1, T2, ..., TN>
- holds object of any of types
T1, T2, ..., TN
-
index()
-
std::get<Index>(variant)
std::any
- holds object of any type
-
type()
-
std::any_cast<Target>(any)
rtti
rtti
- <typeinfo>, typeid, std::type_info, std::bad_typeid
- std::type_info::hash_code, std::type_index
- std::type_info::name(), symbol (de)mangling
- dynamic_cast, downcast, upcast, sidecast, std::bad_cast
- std::variant, std::monostate, std::bad_variant_access
- std::any, std::any_cast
- union
RAII
inheritance
virtual
-
constructor
-
member initializer list
-
destructor
-
default constructor
-
std::initializer_list
-
in-class initializer
-
copy ctor
-
cpy assign op
-
move ctor
-
mv assign op
-
default members
-
deleted members
-
rule of 0
-
rule of 3/5
-
smart-ptrs
-
converting constructor
-
explicit specifier
-
is-a relation
-
has-a relation
-
public inheritance
-
protected members
-
using declaration
-
final specifier
-
private & protected inheritance
-
multiple inheritance
-
diamond problem
-
empty base optimization
-
base method hiding problem (shadowing)
-
virtual methods
-
override specifier
-
dynamic type
-
RTTI
-
dynamic_cast
-
typeid
-
vtables
-
-
by value passing problem (slicing)
-
pure virtual function
-
abstract class
misc
-
friends
-
nested members
-
conversion operators
-
operator overloading
-
member pointers
-
unions
-
std optional
-
std variant
-
std any
-
type ereasure
pimpl
enable shared from this with private inheritance
linkage and static (non-member) functions
Liskov substitution principle
function member ref qualification
constexpr virtual
virtual inheritance
aggregate, pod, literal type
implement class in cpp file
delegation to sister class
RTTI
By Jan Bielak
RTTI
- 786