C++中RTTI 与 typeid 运算符

来源:互联网 发布:金山强力卸载软件 编辑:程序博客网 时间:2024/05/21 09:53
<1>RTTI:

标准C++的一个新特征是RTTIRun-Time Type Information运行时类型信息),它为程序在运行时确定对象类型,提供了一种标准方法。

在标准C++中,有三个支持RTTI的元素:

1.   关键字dynamic_cast(动态强制转换):操作符dynamic_cast将一个指向基类的指针或者引用转换为一个指向派生类的指针或引用

 (如果不能正确转换,则返回0——空指针),格式为:

dynamic_cast < type-id > (exp )

dynamic_cast在转化过程中要用到相关类的类型信息类type_info中的信息。


说明:

(a).如果exp的真实类型是type-id则转换成功;否则转换失败;

(b)在转换失败时,指针类型和引用类型是有区分:

            i. 若exp和type-id都是指针类型,转换是失败返回0;

            ii. 若exp和type-id都是引用类型,则抛出bad_cast 异常;

          //这一点也说明了指针与引用是有区别的!


2.    关键字typeid(类型标识符):用来检测类型(返回type_info类对象的的引用),

         格式为:typeid ( exp )  typeid ( type-id )

     其中,exp结果为对象的表达式,type-id为类名。

   说明: typeid只有作用于类类型时,RTTI的特性才能显现,否则,其他类型都是静态编译时确定的。     

   把typeid作用于指针的解引用*p时,若指针p为0,则:如果p指向的类型是带虚函数的类类型,

     则typeid(*p)在运行时抛出一个bad_typeid异常;


3.      type_info(类型信息):存储特定类型的有关信息,定义在<typeinfo>头文件中。

      type_info类的具体内容由编译器实现来决定,但是至少必须包含返回字符串的name()成员函数。

程序举例:

#include <iostream>#include <typeinfo>  //for 'typeid'using namespace std;class Person {public:   // ... Person members ...   virtual ~Person() {}};class Employee : public Person {   // ... Employee members ...};int main(){   Person person;   Employee employee;   Person *ptr = &employee;   Person &ref = employee;   // The string returned by typeid::name is implementation-defined   std::cout << typeid(person).name() << std::endl;   // Person (statically known at compile-time)   std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time)   std::cout << typeid(ptr).name() << std::endl;      // Person * (statically known at compile-time)   std::cout << typeid(*ptr).name() << std::endl;     // Employee (looked up dynamically at run-time                                                      //           because it is the dereference of a                                                      //           pointer to a polymorphic class)   std::cout << typeid(ref).name() << std::endl;      // Employee (references can also be polymorphic)   Person* p = 0;   try {        typeid(*p); // not undefined behavior; throws std::bad_typeid                  // *p, *(p), *((p)), etc. all behave identically   }catch (...){        cout << "NULL pointer!"<<endl;   }  Person& pRef = *p; // undefined behavior, dereferences null  typeid(pRef);        // does not meet requirements to throw std::bad_typeid  Employee e;  Person pp;  Person &per_ref = pp;  try{    Employee & em_ref = dynamic_cast<Employee&>(per_ref);  }catch(bad_cast e){    cout << "bad cast : not valid type reference !" <<endl;  }catch(...){    cout << "not valid type reference !" <<endl;  }                    // because the expression for typeid is not the result                      // of applying the unary * operator; behavior is undefined}


<2>关于 typeid:

typeid表达式形如:
      typeid(expr);
这里expr是任意表达式或者类型名。如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
 
   typeid操作符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义)。标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作:
 t1 == t2 如果两个对象t1和t2类型相同,则返回true;否则返回false t1 != t2 如果两个对象t1和t2类型不同,则返回true;否则返回false t.name() 返回类型的C-style字符串,类型名字用系统相关的方法产生 t1.before(t2) 返回指出t1是否出现在t2之前的bool值type_info类提供了public虚析构函数,以使用户能够用其作为基类。它的默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符(由此可见,如果把typeid看作函数的话,其应该是type_info的友元)。type_info的name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致(往往如此,见后面的程序),这是由实现所决定的,标准只要求实现为每个类型返回唯一的字符串。例如:

#include <iostream>

using namespace std;

class Base {};
class Derived: public Base {};

int main()
{
    cout << typeid(int).name() << endl
         << typeid(unsigned).name() << endl
         << typeid(long).name() << endl
         << typeid(unsigned long).name() << endl
         << typeid(char).name() << endl
         << typeid(unsigned char).name() << endl
         << typeid(float).name() << endl
         << typeid(double).name() << endl
         << typeid(string).name() << endl
         << typeid(Base).name() << endl
         << typeid(Derived).name() << endl
         << typeid(type_info).name() << endl;
         
    return 0;
}

在MinGW2.05下的运行结果:
i
j
l
m
c
h
f
d
Ss
4Base
7Derived
St9type_info


Terminated with return code 0
Press any key to continue ...

 
   注意:当把typeid作用于指针的解引用*p时,若指针p为0,则:如果p指向的类型是带虚函数的类类型,则typeid(*p)在运行时抛出一个bad_typeid异常;否则,typeid(*p)的结果与p的值是不相关的,在编译时就可以确定。typeid表达式的这点性质与sizeof表达式相似但又有区别,sizeof一定是在编译时进行计算,也就是说,其只考虑表达式的静态类型,与表达式的动态类型无关(即使有虚函数存在)。
 

参考文献:
[1] C++ Primer(Edition 4)
[2] Thinking in C++(Edition 2)
[3] International Standard:ISO/IEC 14882:1998

补充:From Wikipedia, the free encyclopedia:

In C++, the typeid keyword is used to determine the class of an object at run time. It returns a reference to std::type_info object, which exists until the end of the program[1]. The use of typeid is often preferred over dynamic_cast<class_type> in situations where just the class information is needed, because typeid is a constant-time procedure, whereas dynamic_cast must traverse the class derivation lattice of its argument at runtime. Some aspects of the returned object are implementation-defined, such as std::type_info::name(), and cannot be relied on across compilers to be consistent.

Objects of class std::bad_typeid are thrown when the expression for typeid is the result of applying the unary * operator on a null pointer. In other words, the expression must take the form typeid(*p) where p is any expression resulting in a null pointer.


From Wikipedia, the free encyclopedia:

Run-time type information

From Wikipedia, the free encyclopedia

In computer programming, RTTI (Run-Time Type Information, or Run-Time Type Identification) refers to a C++ mechanism that exposes information about an object'sdata type at runtime. Run-time type information can apply to simple data types, such as integers and characters, or to generic types. This is a C++ specialization of a more general concept called type introspection.

In the original C++ design, Bjarne Stroustrup did not include run-time type information, because he thought this mechanism was frequently misused.[1]

Contents

  [hide] 
  • 1 Features
  • 2 C++ Example
  • 3 See also
  • 4 References

[edit]Features

The dynamic_cast<> operation and typeid operator in C++ are part of RTTI.

The C++ run-time type information permits performing safe typecasts and manipulate type information at run time.

RTTI is available only for classes which are polymorphic, which means they have at least one virtual method. In practice, this is not a limitation because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.

RTTI is optional with some compilers; the programmer can choose at compile time whether to include the function. There may be a resource cost to making RTTI available even if the program does not use it.

[edit]C++ Example

/* A base class pointer can point to objects of any class which is derived  * from it. RTTI is useful to identify which type (derived class) of object is  * pointed to by a base class pointer. */ #include <iostream> class abc   // base class{public:  virtual ~abc() { }   virtual void hello()   {    std::cout << "in abc";  }}; class xyz : public abc{  public:  void hello()   {    std::cout << "in xyz";  }}; int main(){  abc *abc_pointer = new xyz();  xyz *xyz_pointer;   // to find whether abc_pointer is pointing to xyz type of object  xyz_pointer = dynamic_cast<xyz*>(abc_pointer);   if (xyz_pointer != NULL)  {    std::cout << "abc_pointer is pointing to a xyz class object";   // identified  }  else  {    std::cout << "abc_pointer is NOT pointing to a xyz class object";  }   // needs virtual destructor   delete abc_pointer;   return 0;}

An instance where RTTI is used is illustrated below:

class base {  public:      virtual ~base(){}}; class derived : public base {  public:    virtual ~derived(){}    int compare (derived &ref);}; int my_comparison_method_for_generic_sort (base &ref1, base &ref2){  derived & d = dynamic_cast<derived &>(ref1); // RTTI used here  // RTTI enables the process to throw a bad_cast exception  // if the cast is not successful  return d.compare (dynamic_cast<derived &>(ref2));}

[edit]See also

  • Reflection

[edit]References

  1. ^ Bjarne Stroustrup. "A History of C++: 1979—1991". p. 50. Retrieved 2009-05-18.




原创粉丝点击