The RTTI mechanism in C + + _c language

Source: Internet
Author: User

Objective

RTTI is the abbreviation for "Runtime type information", meaning Run-time type information, which provides a way to determine the type of object at run time. Rtti is not a new thing, it is very early to have this technology, but in the actual application of the relatively few. And I am here to rtti Summary, today I did not use, does not mean that this thing is useless. Learning first begins with the typeID function.

typeID function

The primary role of typeID is to let users know what type of current variable is, such as the following code:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

int main ()
{
Short S = 2;
unsigned UI = 10;
int i = 10;
char ch = ' a ';
wchar_t WCH = L ' B ';
float F = 1.0f;
Double d = 2;

Cout<<typeid (s). Name () <<endl; Short
Cout<<typeid (UI). Name () <<endl; unsigned int
Cout<<typeid (i). Name () <<endl; Int
Cout<<typeid (CH). Name () <<endl; Char
Cout<<typeid (WCH). Name () <<endl; wchar_t
Cout<<typeid (f). Name () <<endl; Float
Cout<<typeid (d). Name () <<endl; Double

return 0;
}

For the built-in types supported by C + +, typeID can fully support, we can know the information of the variable by calling the typeID function. For our custom structure, what about the class?

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
void Print () {cout<< "This is class A." <<endl; }
};

Class B:public A
{
Public
void Print () {cout<< "This is class B." <<endl; }
};

struct C
{
void Print () {cout<< "This is struct C." <<endl; }
};

int main ()
{
A *pa1 = new A ();
A A2;

Cout<<typeid (pA1). Name () <<endl; Class A *
Cout<<typeid (A2). Name () <<endl; Class A

b *PB1 = new B ();
Cout<<typeid (pB1). Name () <<endl; Class B *

c *PC1 = new C ();
C C2;

Cout<<typeid (pC1). Name () <<endl; struct C *
Cout<<typeid (C2). Name () <<endl; struct C

return 0;
}

Yes, Tpyeid can support our custom structures and classes. In the above code, after typeID is called, the name () function is called, and you can see that the typeID function returns a struct or class, and then calls the name member function of the returned struct or class; in fact, typeID is a return type of type_ A function of type info. Then it is necessary to sum up the Type_info class, after all, it actually holds the type information.

Type_info class

Get rid of those damn macros and view the Type_info class as defined in Visual Studio 2012 as follows:

Copy Code code as follows:

Class Type_info
{
Public
Virtual ~type_info ();
BOOL operator== (const type_info& _RHS) const; To compare the types of two objects for equality
BOOL Operator!= (const type_info& _RHS) const; is used to compare two objects for unequal types
BOOL Before (const type_info& _RHS) const;

Returns the type name of the object, which uses a lot of
Const char* name (__type_info_node* __ptype_info_node = &__type_info_root_node) const;
Const char* Raw_name () const;
Private
void *_m_data;
Char _m_d_name[1];
Type_info (const type_info& _RHS);
type_info& operator= (const type_info& _RHS);
static const char * _name_base (const type_info *,__type_info_node* __ptype_info_node);
static void _type_info_dtor (Type_info *);
};

In the Type_info class, both the copy constructor and the assignment operator are private and there is no default constructor; Therefore, we have no way to create type_info class variables, such as Type_info A; this is wrong. So how does the typeID function return a reference to an object of the Type_info class? I do not discuss here, thinking is the friend function of the class.

The use of typeID functions

typeID is very simple to use, the following two kinds of common methods:

1. Use the name () function in the Type_info class to return the type name of an object

Just like the one in the code above, but here's one thing to be aware of, like the following code:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
void Print () {cout<< "This is class A." <<endl; }
};

Class B:public A
{
Public
void Print () {cout<< "This is class B." <<endl; }
};

int main ()
{
A *pa = new B ();
Cout<<typeid (PA). Name () <<endl; Class A *
Cout<<typeid (*PA). Name () <<endl; Class A
return 0;
}

I used the typeid two times, but the two parameters are different; the output is not the same; when I specify PA, because the PA is a pointer of type A, the output is Class A *; When I specify *PA, it represents the type of object that the PA points to. So the output is Class A; so you need to distinguish between typeid (*PA) and typeID (PA), they are two not the same thing, but there is a problem here, clearly the PA is actually pointing to B, why is it the Class A? We're looking at the next piece of code:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
virtual void Print () {cout<< "This is class A." <<endl; }
};

Class B:public A
{
Public
void Print () {cout<< "This is class B." <<endl; }
};

int main ()
{
A *pa = new B ();
Cout<<typeid (PA). Name () <<endl; Class A *
Cout<<typeid (*PA). Name () <<endl; Class B
return 0;
}

Well, I turned the print function into a virtual function, and the output was different, what does that mean? That's Rtti. When a virtual function does not exist in a class, typeID is a compile-time thing, a static type, as above Cout<<typeid (*PA). Name () <<endl; Output Class A When a virtual function exists in a class, the typeid is a run-time thing, that is, a dynamic type, as above Cout<<typeid (*PA). Name () <<endl; output Class B, on this, we are in actual programming, Always make mistakes, and be sure to remember.

2. Use the overloaded = = and!= in the Type_info class to compare whether two objects are of equal type

This is often used to compare objects of two classes with virtual functions for equality, such as the following code:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
virtual void Print () {cout<< "This is class A." <<endl; }
};

Class B:public A
{
Public
void Print () {cout<< "This is class B." <<endl; }
};

Class C:public A
{
Public
void Print () {cout<< "This is class C." <<endl; }
};

void Handle (A *a)
{
if (typeid (*a) = = typeID (a))
{
cout<< "I am a a truly." <<endl;
}
else if (typeid (*a) = = typeID (B))
{
cout<< "I am a B truly." <<endl;
}
else if (typeid (*a) = = typeID (C))
{
cout<< "I am a C truly." <<endl;
}
Else
{
cout<< "I am alone." <<endl;
}
}

int main ()
{
A *pa = new B ();
Handle (PA);
Delete PA;
PA = new C ();
Handle (PA);
return 0;
}

This is a usage, and I'll summarize how to use dynamic_cast to achieve the same function.

The inside of dynamic_cast

In this article "static_cast, dynamic_cast, const_cast and reinterpret_cast Summary", also introduced the use of dynamic_cast, for dynamic_cast in the end is how to achieve, There is no explanation, and here is a dynamic_cast insider. First look at a piece of code:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
virtual void Print () {cout<< "This is class A." <<endl; }
};

Class B
{
Public
virtual void Print () {cout<< "This is class B." <<endl; }
};

Class C:public A, public B
{
Public
void Print () {cout<< "This is class C." <<endl; }
};

int main ()
{
A *pa = new C;
C *pc = PA; Wrong
C *pc = dynamic_cast<c *> (PA);
if (PC!= NULL)
{
Pc->print ();
}
Delete PA;
}

In the code above, if we assign the PA directly to the PC, the compiler prompts for the error, and when we add the dynamic_cast, everything is OK. So what did dynamic_cast do in the back?

Dynamic_cast is primarily used in polymorphism when it allows type conversions at run time, allowing programs to safely convert types in a class hierarchy and convert base class pointers (references) to derived class pointers (references). As I concluded in the post "COM programming--Interface behind", when a virtual function exists in a class, the compiler adds a vptr pointer to the virtual function table in the class's member variable, and the Type_info object associated with each class is also passed through virtual Table is pointed out, usually this Type_info object is placed in the first slot of the table. When we do dynamic_cast, the compiler will help us with the grammar check. If the pointer's static type is the same as the target type, then nothing is done; otherwise, the pointer is first adjusted so that it points to vftable and passes it and the adjusted pointer, the adjusted offset, the static type, and the target type to the internal function. The last argument indicates whether the conversion is a pointer or a reference. The only difference is that if the conversion fails, the former returns null, and the latter throws a Bad_cast exception. For the program that is used in the use of the typeID function, I use dynamic_cast to change the code as follows:

Copy Code code as follows:

#include <iostream>
#include <typeinfo>
using namespace Std;

Class A
{
Public
virtual void Print () {cout<< "This is class A." <<endl; }
};

Class B:public A
{
Public
void Print () {cout<< "This is class B." <<endl; }
};

Class C:public A
{
Public
void Print () {cout<< "This is class C." <<endl; }
};

void Handle (A *a)
{
if (dynamic_cast<b*> (a))
{
cout<< "I am a B truly." <<endl;
}
else if (dynamic_cast<c*> (a))
{
cout<< "I am a C truly." <<endl;
}
Else
{
cout<< "I am alone." <<endl;
}
}

int main ()
{
A *pa = new B ();
Handle (PA);
Delete PA;
PA = new C ();
Handle (PA);
return 0;
}

This is the version that is rewritten using dynamic_cast. In the actual project, this method will use more points.

Summarize

I have summed up the relevant knowledge of rtti here, I hope you can understand. This blog is a bit long, I hope you can also be patient to see. Summed up, there will be gains.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.