The <NiklasRosenstein/typeid.hpp>
header provides a manual alternative over
RTTI and dynamic_cast<>()
. It can be used in cases where RTTI is not available
or unknown to be enabled. At the same time, nr::type_cast<>()
addresses a
common problem with side-casts which can be very troublesome when using
dynamic_cast<>()
.
#include <NiklasRosenstein/typeid.hpp>
namespace nr = niklasrosenstein;
struct Base {
NR_TYPEID(Base, 1);
};
struct InterfaceA : public virtual Base {
NR_TYPEID(InterfaceA, 2);
virtual std::string do_a_stuff() = 0;
};
struct InterfaceB : public virtual Base {
NR_TYPEID(InterfaceB, 3);
virtual std::string do_b_stuff() = 0;
};
class Impl : public virtual InterfaceA, virtual InterfaceB {
NR_TYPEID(Impl, 4);
public:
virtual std::string do_a_stuff() override { return "A stuff"; }
virtual std::string do_b_stuff() override { return "B stuff"; }
std::string do_impl_stuff() { return "Impl Stuff"; }
};
Base* get_some_implementation() {
return new Impl;
}
int main() {
Base* base = get_some_implementation();
// Up-cast from Base.
InterfaceA* a = nr::type_cast<InterfaceA>(base);
// Side-cast from InterfaceA.
InterfaceB* b = nr::type_cast<InterfaceB>(a);
// Up-cast from InterfaceB.
Impl* i = nr::type_cast<Impl>(b);
std::cout << a->do_a_stuff() << std::endl;
std::cout << b->do_b_stuff() << std::endl;
std::cout << i->do_impl_stuff() << std::endl;
del base;
}
nr::type_id<T>()
This template overloads the ID for a specific type and can be used to
retrieve the ID of a type that implements the NR_TYPEID()
macro or
for which NR_TYPEID_EX()
has been declared
std::cout << nr::type_id<SomeType>() << std::endl;
NR_TYPEID(cls, id, ...)
This macro makes a class compatible to the type casting system provided
with this lirbary. It assigns a type_id
member and creates two functions
named __virtual_cast()
and __nonvirtual_cast()
as well as some required
friend declarations to allow the macro be placed in the private section.
Parameter | Description |
---|---|
cls | The name of the class for which the type ID is implemented. |
id | An unsigned integer ID that uniquely identifies the type in its valid domain. Two different types may have the same type ID if they are never used in the same context. |
... | The base classes of cls. Can be empty. |
Example
class SomeType : public virtual BaseClass1, virtual BaseClass2 {
NR_TYPEID(SomeType, 8, BaseClass1, BaseClass2);
public:
// ...
};
NR_TYPEID_EX(type, id)
Associate an external class with a type ID. This allows you to assign
a type ID to a type that does not provide a type_id
member.
nr::type_cast<R, T>(T*)
Alternative to dynamic_cast<R>()
. Can only be used with types that implement
the NR_TYPEID()
macro. Supports casts in all directions (up, down and side).
BaseClass1* impl = get_some_implementation();
BaseClass2* b2 = nr::type_cast<BaseClass2>(impl);
if (b2) {
// ...
}
SomeType* st = nr::type_cast<SomeType>(impl);
if (st) {
// ...
}
nr::type_adapter<T>
A class that applies nr::type_cast<T>()
on the pointer that it is passed.
This class is a very convenient helper for function arguments that expect
a class that implements a specific interface.
bool myfunction(nr::type_adapter<InterfaceA> impl) {
if (!impl) return false;
impl->do_stuff();
return true;
}