This example is much shorter, since most of the code in the original example was just the overhead for checking the casts. The target type of a dynamic_cast is placed in angle brackets, like the other new-style C++ casts (static_cast, and so on), and the object to cast appears as the operand. dynamic_cast requires that the types you use it with be
You can also use dynamic_cast with references instead of pointers, but since there is no such thing as a null reference, you need another way to know if the cast fails. That "other way" is to catch a bad_cast exception, as follows:
Metal m;
Security& s = m;
try {
Investment& c = dynamic_cast
cout << " it's an Investment\n";
}
catch (bad_cast&) {
cout << "s is not an Investment type\n";
}
The bad_cast class is defined in the
The typeid operator
The other way to get runtime information for an object is through the typeid operator. This operator returns an object of class type_info, which yields information about the type of object to which it was applied. If the type is polymorphic, it gives information about the most derived type that applies (the
//: C08:TypeInfo.cpp
// Illustrates the typeid operator
#include
#include
using namespace std;
struct PolyBase {virtual ~PolyBase(){}};
struct PolyDer : PolyBase {};
struct NonPolyBase {};
struct NonPolyDer : NonPolyBase {NonPolyDer(int){}};
int main() {
// Test polymorphic Types
const PolyDer pd;
const PolyBase* ppb = &pd
cout << typeid(ppb).name() << endl;
cout << typeid(*ppb).name() << endl;
cout << boolalpha << (typeid(*ppb) == typeid(pd))
<< endl;
cout << (typeid(PolyDer) == typeid(const PolyDer))
<< endl;
// Test non-polymorphic Types
const NonPolyDer npd(1);
const NonPolyBase* nppb = &npd
cout << typeid(nppb).name() << endl;
cout << typeid(*nppb).name() << endl;
cout << (typeid(*nppb) == typeid(npd))
<< endl;
// Test a built-in type
int i;
cout << typeid(i).name() << endl;
} ///:~
The output from this program is
struct PolyBase const *
struct PolyDer
true
true
struct NonPolyBase const *
struct NonPolyBase
false
int
The first output line just echoes the static type of ppb because it is a pointer. To get RTTI to kick in, you need to look at the object a pointer or reference is connected to, which is illustrated in the second line. Notice that RTTI ignores top-level const and volatile qualifiers. With non-polymorphic types, you just get the static type (the type of the pointer itself). As you can see, built-in types are also supported.
It turns out that you can’t store the result of a typeid operation in a type_info object, because there are no accessible constructors and assignment is disallowed; you must use it as we have shown. In addition, the actual string returned by type_info::name( ) is compiler dependent. Some compilers return "class C" instead of just "C", for instance, for a class named C. Applying typeid to an expression that dereferences a null pointer will cause a bad_typeid exception (also defined in
The following example shows that the class name that type_info::name( ) returns is fully qualified.
//: C08:RTTIandNesting.cpp
#include
#include
using namespace std;
class One {
class Nested {};
Nested* n;
public:
One() : n(new Nested) {}
~One() { delete n; }
Nested* nested() { return n; }
};
int main() {
One o;
cout << typeid(*o.nested()).name() << endl;
} ///:~
Since Nested is a member type of the One class, the result is One::Nested.
You can also ask a type_info object if it precedes another type_info object in the implementation-defined "collation sequence" (the native ordering rules for text), using before(type_info&), which returns true or false. When you say,.
if(typeid(me).before(typeid(you))) // ...
you’re asking if me occurs before you in the current collation sequence. This is useful should you use type_info objects as keys.
Casting to intermediate levels