Type recognition in c++

1. Concepts related to type recognition

(1) Role of type recognition

Type recognition is a new concept introduced in object-oriented to determine the type problem in the assignment compatibility principle, that is, whether the data type at this time is a class type or a derived class type?

Type recognition is required when the base class pointer points to a subclass object or when the base class references an alias that becomes a subclass object.

1 Base *p = new Derived();
2 Base &r = *p

(As we can see from the above statement, pointer P is of Base type, but P points to a new Derived type, so it is difficult to determine the data type of pointer P. Similarly, reference r originally exists as an alias for the parent class, but due to the compatibility of assignments, reference R can also be used as an alias for the subclass, and at this time reference RThe data type is also uncertain;

Note: 1) As previously learned, without virtual function overrides, the compiler will treat pointer p as a Base type for security purposes; (during compilation)

2) If there is a virtual function override, the dynamic polymorphism will occur, and the data type of pointer p will be determined according to the specific data type pointed to by the pointer p.(during operation)

(2) Classification of type recognition

    

1) Static type: The type of variable (object) itself; the data type of the variable used can be determined at the compilation stage.

(2) Dynamic type: the actual type of object pointed to by the pointer (reference); at run time, the data type used is determined by the specific data type pointed by the pointer.

    

The actual object pointed to by Base *b cannot be determined. If pointer B is pointing to a subclass object, the program will run normally; if pointer B is pointing to a parent object, the program may have a Bug;

Note: This works well with the g++ compiler, but the latter is not recommended.

In the Assignment Compatibility Principle, whether a base class pointer can force a type to be converted to a subclass pointer depends on the dynamic type; (Important!!!)- Only dynamic types can be legally converted if they are subclass objects

2. How to get dynamic types

(1) Utilizing polymorphism

1) Type virtual functions must be provided from the base class;

2) All derived classes must override type virtual functions;

3) The type ID of each derived class must be unique;

Result: By calling the type virtual function, you can know what type the current object is, so that you can get the dynamic type and achieve the dynamic type recognition effect.

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Base
 7 {
 8 public:
 9     enum { ID = 0 };
10     
11     virtual int type()  // Type virtual function
12     {
13         return ID;
14     }
15 };
16  
17 class Derived : public Base
18 {
19 public:
20     enum { ID = 1 };
21     
22     int type()
23     {
24         return ID;
25     }
26     
27     void print()
28     {
29         cout << "I'm a Derived. " << endl;
30     }
31 };
32 
33 class Child : public Base
34 {
35 public:
36     enum { ID = 2 };
37     
38     int type()
39     {
40         return ID;
41     }
42 };
43  
44 void test(Base* pb)
45 {
46     if( pb->type() == Child::ID )
47     {
48         Child* pc = static_cast<Child*>(pb);
49         //Child* pc = dynamic_cast<Child*>(pb);   // Ditto
50         
51         cout << "& = " << pc << endl;
52         cout << "I'm a Child. " << endl;
53     }
54     
55     if( pb->type() == Derived::ID )
56     {
57         Derived* pd = static_cast<Derived*>(pb);
58         //Derived* pd = dynamic_cast<Derived*>(pb); // Ditto
59         
60         cout << "& = " << pd << endl;
61         pd->print();
62     }
63     
64     if( pb->type() == Base::ID )
65     {
66         cout << "& = " << pb << endl;
67         cout << "I'm a Base. " << endl;
68     }
69 }
70  
71 int main(int argc, char *argv[])
72 {
73     Base b;
74     Derived d;
75     Child c;
76     
77     test(&b);
78     test(&d);
79     test(&c);
80     
81     return 0;
82 }
83 /**
84  * Run result:
85  * & = 0x7ffccf0dd850
86  * I'm a Base. 
87  * & = 0x7ffccf0dd860
88  * I'm a Derived.
89  * & = 0x7ffccf0dd870
90  * I'm a Child.
91  */
Type Recognition Using Type Virtual Functions

 

(2) Using dynamic_cast

1) dynamic_cast returns NULL if the actual type to be converted is not the same as the specified type.For example, when the specified type is a subclass object, if the dynamic type of the parent pointer is this subclass object, the conversion succeeds, and if the dynamic type is a parent object or other subclass object, the conversion fails.

2) The type of target object required by dynamic_cast must be polymorphic, that is, there must be at least one virtual function in the class family in which it belongs;

3) Can only be used for conversion between pointer and reference

1. When used for pointer conversion, the conversion fails and a null pointer is returned;

2. When used for reference conversion, the conversion fails and a bad_cast exception is thrown.

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Base
 7 {
 8 public:
 9     virtual ~Base()
10     {
11     
12     }
13 };
14  
15 class Derived : public Base
16 {
17 public:    
18     void print()
19     {
20         cout << "I'm a Derived. " << endl;
21     }
22 };
23 
24 class Child : public Base
25 {
26 
27 };
28  
29 void test(Base* pb)
30 {
31     // dynamic_cast Only final transformation results can be determined, no prototype of dynamic type can be obtained
32     Derived* pd = dynamic_cast<Derived*>(pb);
33     
34     if(pd != NULL)
35     {
36         // Derived Class type, you can use pointers pd Visit Derived Members of the class
37         cout << "& = " << pd << endl;
38         pd->print();
39     }
40     else
41     {
42         Child* pc = dynamic_cast<Child*>(pb);
43         
44         if(pc != NULL)
45         {
46             // Child Class type, you can use pointers pc Visit Child Members of the class
47             cout << "& = " << pc << endl;
48             cout << "I'm a Child. " << endl;
49         }
50         else
51         {
52             // Base Class type, you can use pointers pb Visit Base Members of the class
53             cout << "& = " << pc << endl; 
54             cout << "I'm a Base. " << endl;
55         }
56     }
57 }
58  
59 int main(int argc, char *argv[])
60 {
61     Base b;
62     Derived d;
63     Child c;
64     
65     test(&b);
66     test(&d);
67     test(&c);
68     
69     return 0;
70 }
71 /**
72  * Run result:
73  * & = 0
74  * I'm a Base. 
75  * & = 0x7ffccf0dd860
76  * I'm a Derived.
77  * & = 0x7ffccf0dd870
78  * I'm a Child.
79  */
Type Recognition Using dynamic_cast

 

(3) Using typeid (recommended method)

1) typeid is a keyword specifically for dynamic type recognition;

2) The typeid keyword returns the type information of the corresponding parameter, which is a type_info class object;

1. Returns static type information when the parameter is of type;

2. When the parameter is a variable: 1> When there is no virtual function table inside the parameter variable, static type information is returned; 2> When there is a virtual function table inside the parameter variable, dynamic type information is returned;

3. When the parameter is NULL, an exception will be thrown;

3) typeid needs to include header file <typeinfo> when using;

4) Specify the object or type directly when typeid is used.

5) Typeeid implementations are different within different compilers;

1 int i = 0;
2        
3 const type_info& tiv = typeid(i);  // take i Type information for type_info To go;
4 const type_info& tii = typeid(int);
5        
6 cout << (tiv == tii) << endl;  // 1

 

  1 #include <iostream>
  2 #include <string>
  3 #include <typeinfo>
  4 
  5 using namespace std;
  6 
  7 class Base
  8 {
  9 public:
 10     virtual ~Base()
 11     {
 12     }
 13 };
 14  
 15 class Derived : public Base
 16 {
 17 public:
 18     void print()
 19     {
 20         cout << "I'm a Derived." << endl;
 21     }
 22 };
 23  
 24 class Child : public Base 
 25 {
 26 public:
 27     void print()
 28     {
 29         cout << "I'm a Child." << endl;
 30     }
 31 };
 32  
 33 void test(Base* pb)
 34 {
 35     const type_info& tb = typeid(*pb);
 36     
 37     if( tb == typeid(Derived) )
 38     {
 39         Derived* pd = dynamic_cast<Derived*>(pb);
 40     
 41         cout << "& = " << pd << endl;
 42         pd->print();
 43     }
 44     else if( tb == typeid(Child) )
 45     {
 46         Child* pc = dynamic_cast<Child*>(pb);
 47         
 48         cout << "& = " << pc << endl;
 49         pc->print();
 50         
 51     }
 52     else if( tb == typeid(Base) )
 53     {
 54         cout << "& = " << pb << endl;
 55         cout << "I'm a Base. " << endl;
 56     }
 57     
 58     cout << tb.name() << endl;
 59 }
 60  
 61 int main(int argc, char *argv[])
 62 {
 63     Base b;
 64     Derived d;
 65     Child c;
 66     int index;
 67     char ch;
 68     
 69     const type_info& tp = typeid(b);
 70     const type_info& tc = typeid(d);
 71     const type_info& tn = typeid(c);
 72     const type_info& ti = typeid(index);
 73     const type_info& tch = typeid(ch);
 74     
 75     cout<<tp.name()<<endl;
 76     cout<<tc.name()<<endl;
 77     cout<<tn.name()<<endl;
 78     cout<<ti.name()<<endl;
 79     cout<<tch.name()<<endl;
 80     
 81     test(&b);
 82     test(&d);
 83     test(&c);
 84     
 85     return 0;
 86 }
 87 /**
 88  * Run result:
 89  * 4Base
 90  * 7Derived
 91  * 5Child
 92  * i
 93  * c
 94  * & = 0x7ffcbd4d6280
 95  * I'm a Base. 
 96  * 4Base
 97  * & = 0x7ffcbd4d6290
 98  * I'm a Derived.
 99  * 7Derived
100  * & = 0x7ffcbd4d62a0
101  * I'm a Child.
102  * 5Child
103  */ 
Type Recognition Using Typeeid

The third (typeid) is recommended for the implementation of the three dynamic types.

For polymorphic implementations, there are the following drawbacks:

1) Type virtual functions must be provided from the base class;

2) All derived classes must override type virtual functions;

3) Each derived class must have a unique type name;

For dynamic_cast implementations, only the result of type conversion can be obtained, not the true dynamic type, and dynamic_cast must be polymorphic.

Tags: C++

Posted on Fri, 13 Mar 2020 13:07:59 -0400 by sandeepjayan