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
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_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);
typeid(*p)
PolymorphicT p{}; // 0 initialized
typeid(*p); // std::bad_typeid
where p == nullptr
throw std::bad_typeid
no UB
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
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++
constexpr auto name = typeid(int).name();
...
...
VFTablePtr
struct B1 {
...
virtual void foo() {}
};
struct D1 : B1 { ... };
struct B2 {
...
virtual void bar() {}
}
struct D2 : D1, B2 { ... }
...
...
VFTablePtr
top_offset = 0
typeinfo for D2
B1::foo
top_offset = -8
typeinfo for D2
B2::bar
...
...
mangled_name
example under g++
under libstdc++ (g++) and libc++ (Clang)
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
-fno-rtti
/GR-
under G++, Clang and similar
under MSVC
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';
}
std::variant<T1, T2, ..., TN>
T1, T2, ..., TN
index()
std::get<Index>(variant)
std::any
type()
std::any_cast<Target>(any)
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