Reputation: 13701
I have a pointer to a polymorphic type, p
. I also have a type_info
for a class somewhere in the same hierarchy, ti
.
If I just compare the typeid(*p) == ti
, then I can test at runtime whether the pointer is pointing to a direct instance of that class.
Is there a similar way to use C++'s RTTI to test whether *p
inherits from that class?
Upvotes: 4
Views: 6713
Reputation: 659
Great thanks to Flexo. I have been researching the C++ ABI for a quite while. After a hour of work, I've got this demo: http://pastebin.com/j7DYY5ej. Here is a code to check inheritance in some cases. I've implemented operators ==, !=, <, >, <=, >= for the types. I'm planning to improve this way of type equation and to use it in my project. Note that I used G++ 4.8 under Linux.
Upvotes: 0
Reputation: 88731
There's no way to do this in standard C++ alone. If you're using an implementation that has the Itanium C++ ABI1 you can do this though, for example:
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <memory>
class base {
protected:
base() {
}
public:
static bool check(const std::type_info& p) {
// Find the real type_info for single inheritance non virtual
const __cxxabiv1::__si_class_type_info* test = dynamic_cast<const __cxxabiv1::__si_class_type_info*>(&p);
return test ? typeid(base) == *test->__base_type : false;
}
virtual ~base() {}
};
class der : public base {
};
class foo {};
int main() {
der d;
foo f;
std::cout << base::check(typeid(d)) << "\n";
std::cout << base::check(typeid(f)) << "\n";
}
Here this works because the type has a single, non-virtuallly inherited base. You can support more cases though with care and similar dynamic_casts
.
Whilst this is possible under these certain circumstances I think you're solving the wrong problem though - a solution based around a std::map
is more portable and avoids relying on implementation details like this.
1 confusingly named, it's a surprisingly large compiler/architecture list, not just Itanium
Upvotes: 2
Reputation: 2270
Yes, you can use dynamic_cast<>
for that purpose. If you try to cast to Base*
, it performs a runtime check to see if your class really is derived from Base
(or directly is a Base). In case of failure, dynamic_cast<>
returns nullptr
. Example :
struct Base {
virtual ~Base() {}
};
struct AnotherBase {
virtual ~Base() {}
};
struct Derived : Base {};
Base * basePtr = new Base();
Base * derivedPtr = new Derived();
AnotherBase * anotherBasePtr = new Base();
// is derivedPtr a pointer to a class derived from AnotherBase ?
AnotherBase* test2 = dynamic_cast<AnotherBase*>(derivedPtr); // test2 == nullptr
// is basePtr a pointer to a class derived from Derived ?
Derived * test3 = dynamic_cast<Derived*>(basePtr); // test3 == nullptr
Side nodes :
if dynamic_cast<>
is used to convert pointers, it returns either nullptr
or the converted pointer.
BUT when dynamic_cast<>
is used to convert references it throws an exception in case of failure.
The runtime check of dynamic_cast<>
is only possible for polymorphic types. If your Base doesn't contain any virtual function (= non polymorphic), it won't be possible to safely convert a Base*
to a Derived*
.
Upvotes: 1