Model to the intermediate layer
As you can use in front of the Security class level, Dynamic_cast can detect the original type and intermediate type in a plurality of layers. Here is another example:
//: c08: intermediatecast.cpppp
#include
#include
Using namespace std;
Class b1 {
PUBLIC:
Virtual ~ b1 () {}
}
Class b2 {
PUBLIC:
Virtual ~ b2 () {}
}
Class MI: Public B1, Public B2 {};
Class Mi2: public mi {};
Int main () {
B2 * b2 = new mi2;
Mi2 * mi2 = Dynamic_cast
Mi * mi = Dynamic_cast
B1 * b1 = Dynamic_cast
Assert (TypeID (b2)! = TypeId (mi2 *));
ASSERT (TypeId (B2) == TypeId (b2 *));
Delete B2;
} ///: ~
This example has multiple inheritance of additional complexity (you learned more about multiple inheritance in Character 9 of this chapter). If you create a MI2 and convert him up to the root (in this case, one of the two possible roots is selected), Dynamic_cast returns to the inheritance layer Mi or Mi2 is successful.
You can even create from one root to another:
B1 * b1 = Dynamic_cast
This is successful because B2 is in fact pointing to a MI2 object, which contains a sub-object of a type B1.
An interesting difference between Dynamic_CAST and TYPEID is made to the intermediate layer. The TypeID operator often generates a reference to a static Type_info object, which describes the dynamic type of the object. Therefore, he will not give you the information of the intermediate layer. In the following expression (it is true), TypeID does not view B2 as a pointer to the derived type, like Dynamic_cast:
TYPEID (B2)! = TypeId (mi2 *)
The type of B2 is the actual type of the pointer: TypeID (b2) == TypeID (b2 *)
Void pointer
RTTI only works on a complete type, meaning that all class information may be used when using TypeID. Special, it does not work on the Void pointer:
//: c08: voidrtti.cpp
// rtti & void pointers.
//! # include
#include
Using namespace std;
Class stimpy {
PUBLIC:
Virtual void happy () {}
Virtual void joy () {}
Virtual ~ stimpy () {}
}
Int main () {
Void * v = new stimpy;
// Error:
//! Stimpy * s = dynamic_cast
// Error:
//! Cout << TypeId (* v) .Name () << Endl;
} ///: ~
Void actually means "there is no type of information".
RTTI for template
Class template and RTTI work normally because all things are to generate classes. As usual, RTTI provides a way to facilitate the name of your class. The following example prints out the order of constructor and destructive function calls. //: c08: constructororder.cpp
// Order of Constructor Calls.
#include
#include
Using namespace std;
Template
PUBLIC:
Announce () {
COUT << TypeId (* this) .Name () << "constructor" << Endl;
}
~ Announce () {
COUT << TypeId (* this) .Name () << "destructor" << endl;
}
}
Class x: public announce <0> {
Announce <1> m1;
Announce <2> M2;
PUBLIC:
X () {cout << "x :: x ()" << endl;}
~ X () {cout << "x :: ~ x ()" << endl;}
}
INT main () {x x;} ///: ~
This template distinguishes a class and another class with a constant integer, but the type parameter can work. Inside the constructor and the destructor, the RTTI information generates a printed class name. Class X uses inheritance and combination to generate a class, which is fun. The output is:
Announce <0> Constructor
Announce <1> Constructor
Announce <2> Constructor
X :: x ()
X :: ~ x ()
Announce <2> Destructor
Announce <1> Destructor
Announce <0> Destructor
Of course, you can also get different outputs, depending on how your compiler shows its name () information.