RTTIwith Run-time type recognition (RTTI), programs can use pointers or references to base classes to retrieve thesethe actual derived type of the object that the pointer or reference refers to. RTTI is provided using the following two operators: 1. The typeid operator returns the actual type of the object that the pointer or reference refers to . 2. dynamic_cast operator to safely convert a pointer or reference of a base class type to a derived typepointer or reference. These operators return dynamic type letters only for classes with one or more virtual functions Interest, for other types, returns information for static (that is, compile-time) types. for classes with virtual functions, the RTTI operator is executed at run time, but for other types, the compilationwhen the RTTI operator is evaluated. When you have a reference or pointer to a base class, but you need to perform a derived class operation that is not part of the base classrequires dynamic coercion of type conversions. In general, the best way to get derived class behavior from a base class pointer is tothrough virtual functions. When using virtual functions, the compiler automatically chooses the correct object based on its actual type .function. However, in some cases, virtual functions cannot be used. In these cases, RTTI provides anselected mechanism. However, this mechanism is more error-prone than using virtual functions: The programmer must know that thelike cast to which type, and you must check whether the conversion executed successfully. use dynamic coercion to type conversions with caution. Whenever possible, define and use a virtual letternumber is much better than direct takeover type management.
dynamic_castconverts a reference or pointer of a base class type object to the samea reference or pointer to another type in the inheritance hierarchy. Note: The class that passes in the parameter of the dynamic_cast must have the virtual function , otherwise, the compilation cannot pass. dynamic_cast involves run-time type checking. If the bindingdynamic_cast fails if the object to the reference or pointer is not an object of the target type. If you convert toThe dynamic_cast of the pointer type fails, then the result of the dynamic_cast is a value of 0;to a dynamic_cast of a reference type fails, an exception of type Bad_cast is thrown.
typeid operatortypeid expressions such as:typeid (e);here E is either an arbitrary expression or a type name. If the type of the expression is a class type and the class contains one or more virtual functions, the dynamic type of the expression may be different from its static compile-time type ;The typeid operator can be used with any type of expression. Expressions for built-in types andconstants can be used as operands of the typeid operator. If the operand is not of class type or is not a virtualfunction, the typeid operator indicates the static type of the operand, or if the operand is defined at leastThe class type of a virtual function, the type is evaluated at run time.
The result of the typeid operator is an object reference to the standard library type named Type_info .to use the Type_info class, you must include the library header fileTypeInfo. The most common use of typeid is to compare the types of two expressions, or to type the expression with a specialComparison of the fixed type: only if the operand of typeid is an
object of class type with a virtual function , To return dynamic type information. The test pointer (relative to the object pointed to by the pointer) returnsThe static, compile-time type of the pointer back. if the value of the pointer p is 0, then if the type of P is a type with a virtual function, thetypeID (*p) throws a Bad_typeid exception, if the type of p does not have any virtual functions defined,The result is not related to the value of P. Just like the computational expression sizeof,The translator does not calculate *p, which uses the static type of p, which does not require that P itself be a valid pointer.
Example
#include <iostream> #include <typeinfo>using namespace Std;class base{public:virtual void func () {cout << "I, Base." << Endl;}}; Class Derived:public base{public:void Dfunc () {cout << "I, Derived." << Endl;}}; Class badderived{public:virtual void Func () {cout << "I, badderived." << Endl;}}; Class t{Public:void Dfunc () {cout << "I, T." << Endl;}}; int main () {Base *baseptr = new Derived; badderived *badptr = new badderived; cout << Endl << "*********test 0************" << Endl; if (T *deriveptr = dynamic_cast<t*> (baseptr)) {cout << "success---->"; Deriveptr->dfunc (); } else {cout << "failed----->"; Baseptr->func (); cout << "DEBUG" << Endl; cout << "typeID (t). Name =" << typeid (t). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (*baseptr). Name () << Endl; } cout << Endl << "*********test 1************" << Endl; if (Derived *deriveptr = dynamic_cast<derived*> (baseptr)) {cout << "success---->"; Deriveptr->dfunc (); } else {cout << "failed----->"; Baseptr->func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" << typeid (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (*baseptr). Name () << Endl; } cout << Endl << "*********test 2************" << Endl; if (Derived *deriveptr = dynamic_cast<derived*> (badptr)) {cout << "success---->"; Deriveptr->dfunc (); } else {cout << "failed----->"; BaDptr->func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" << typeid (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (*badptr). Name () << Endl; } Derived Deriveobj; Base &baseref = deriveobj; Badderived Badobj; badderived &badref = badobj; cout << Endl << "*********test 3************" << Endl; try {Derived &deriveref = dynamic_cast<derived&> (baseref); cout << "Success---->"; Deriveref.dfunc (); } catch (Bad_cast) {cout << "failed----->"; Baseref.func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" << typeid (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (baseref). Name () << Endl; } cout << Endl << "*********test 4************ "<< Endl; try {Derived &deriveref = dynamic_cast<derived&> (badref); cout << "Success---->"; Deriveref.dfunc (); } catch (Bad_cast) {cout << "failed----->"; Baseref.func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" << typeid (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (badref). Name () << Endl; } cout << Endl << "*********test 5************" << Endl; if (typeid (Derived) = = typeID (baseref)) {Derived &deriveref = dynamic_cast<derived&> (baseref); cout << "Success---->"; Deriveref.dfunc (); } else {cout << "failed----->"; Baseref.func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" <&Lt typeID (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (baseref). Name () << Endl; } cout << Endl << "*********test 6************" << Endl; if (typeid (Derived) = = typeID (badref)) {Derived &deriveref = dynamic_cast<derived&> (badref); cout << "Success---->"; Deriveref.dfunc (); } else {cout << "failed----->"; Badref.func (); cout << "DEBUG" << Endl; cout << "typeID (Derived). Name =" << typeid (Derived). Name () << Endl; cout << "typeID (baseref). Name =" << typeid (badref). Name () << Endl; }}
Execution ResultsTest 0************
Failed----->i, Base.
DEBUG
typeID (T). Name = 1T
typeID (baseref). Name = 7Derived
Test 1************
Success---->i, Derived.
Test 2************
Failed----->i, badderived.
DEBUG
typeID (Derived). Name = 7Derived
typeID (baseref). Name = 10BadDerived
Test 3************
Success---->i, Derived.
Test 4************
Failed----->i, Base.
DEBUG
typeID (Derived). Name = 7Derived
typeID (baseref). Name = 10BadDerived
Test 5************
Success---->i, Derived.
Test 6************
Failed----->i, badderived.
DEBUG
typeID (Derived). Name = 7Derived
typeID (baseref). Name = 10BadDerived
Type Conversions
C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力。
类型转换的不安全来源于两个方面:其一是类型的窄化转化,会导致数据位数的丢失;其二是在类继承链中,将父类对象的地址(指针)强制转化成子类的地址(指针),这就是所谓的下行转换,“下”表示沿着继承链向下走(向子类的方向走)。类似地,上行转换的“上”表示沿继承链向上走(向父类的方向走);上行转换一般是安全的,下行转换很可能是不安全的;因为子类中包含父类,所以上行转换(只能调用父类的方法,引用父类的成员变量)一般是安全的。但父类中却没有子类的任何信息,而下行转换会调用到子类的方法、引用子类的成员变量,这些父类都没有,所以很容易“指鹿为马”或者干脆指向不存在的内存空间。Static_cast <new_type> (expression) static conversion
static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性。dynamic_cast <new_type> (expression) dynamic conversion dynamic conversion ensures that the conversion of a class pointer is appropriate and complete, and that it has two important constraints, one of which isrequire New_type to be a pointer or reference, and the other is the downward transitionrequires that the base class be polymorphic(The base class contains at least one virtual function),如果发现下行转换不安全,dynamic_cast返回一个null指针。 Dynamic_cast is always considered safe when the pointer to be converted is void* or the target pointer is void*. Reinterpret_cast <new_type> (expression) re-interpreting the conversion is the most "unsafe" one, and the conversion between the two classes without any relationship can be implemented with this transformation. Reinterpret_cast can be converted to an address (pointer), this conversion in the system at the bottom of the operation, there is a very strong platform dependency, transplant is not good;requires New_type to be a pointer or reference。 Const_cast <new_type> (expression) constants convert to a very constant amountconst_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。from char *cc = Const_cast<char *> (c) You can see the effect of this conversion, but remember thatThis conversion does not convert the original constant itself, that is, C or constant,just it returns the result cc is very volumeThe
Rtti and type conversions