请输入您要查询的百科知识:

 

词条 Run-time type information
释义

  1. Overview

  2. typeid

     Example 

  3. dynamic_cast and Java cast

     Example 

  4. See also

  5. References

  6. External links

{{expert|Computing|talk=Why is this identified as a C++ thing?}}

In computer programming, run-time type information or run-time type identification (RTTI)[1] is a feature of the C++ programming language that exposes information about an object's data 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. Similar mechanisms are also known in other programming languages, such as Object Pascal (Delphi).

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

Overview

C++ RTTI can be used to do safe typecasts, using the dynamic_cast<> operator, and to manipulate type information at run time, using the typeid operator and std::type_info class.

RTTI is available only for classes that 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 functionality. There may be a resource cost to making RTTI available even if a program does not use it.

typeid

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.[3] The use of typeid, in a non-polymorphic context, is often preferred over dynamic_cast<class_type> in situations where just the class information is needed, because typeid is always a constant-time procedure, whereas dynamic_cast may need to traverse the class derivation lattice of its argument at runtime.{{Citation needed|date=April 2015}} 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. Whether an exception is thrown for other null reference arguments is implementation-dependent. In other words, for the exception to be guaranteed, the expression must take the form typeid(*p) where p is any expression resulting in a null pointer.

Example

  1. include // cout
  2. include // for 'typeid'
 class Person  {    public:       virtual ~Person() {}  };
 class Employee : public Person { };
 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 = nullptr;   try      {       typeid(*p); // not undefined behavior; throws std::bad_typeid      }       catch (...)      {      }
   Person& pRef = *p; // Undefined behavior: dereferencing null   typeid(pRef);      // does not meet requirements to throw std::bad_typeid                      // because the expression for typeid is not the result                      // of applying the unary * operator  }

Output (exact output varies by system and compiler):

 Person Employee Person* Employee Employee

dynamic_cast and Java cast

The dynamic_cast operator in C++ is used for downcasting a reference or pointer to a more specific type in the class hierarchy. Unlike the static_cast, the target of the dynamic_cast must be a pointer or reference to class. Unlike static_cast and C-style typecast (where type check is made during compilation), a type safety check is performed at runtime. If the types are not compatible, an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers).

A Java typecast behaves similarly; if the object being cast is not actually an instance of the target type, and cannot be converted to one by a language-defined method, an instance of java.lang.ClassCastException will be thrown.[4]

Example

Suppose some function takes an object of type A as its argument, and wishes to perform some additional operation if the object passed is an instance of B, a subclass of A. This can be accomplished using dynamic_cast as follows.

  1. include // For std::bad_cast
  2. include // For std::cout, std::err, std::endl etc.

class A {

public:

    // Since RTTI is included in the virtual method table there should be at least one virtual function.    virtual ~A() { };    void methodSpecificToA() { std::cout << "Method specific for A was invoked" << std::endl; };

};

class B : public A {

public:

    void methodSpecificToB() { std::cout << "Method specific for B was invoked" << std::endl; };    virtual ~B() { };

};

void my_function(A& my_a)

{
    try {        B& my_b = dynamic_cast(my_a); // cast will be successful only for B type objects.        my_b.methodSpecificToB();    }    catch (const std::bad_cast& e) {        std::cerr << "  Exception " << e.what() << " thrown." << std::endl;        std::cerr << "  Object is not of type B" << std::endl;    }

}

int main()

{
    A *arrayOfA[3];          // Array of pointers to base class (A)    arrayOfA[0] = new B();   // Pointer to B object    arrayOfA[1] = new B();   // Pointer to B object    arrayOfA[2] = new A();   // Pointer to A object    for (int i = 0; i < 3; i++) {        my_function(*arrayOfA[i]);        delete arrayOfA[i];  // delete object to prevent memory leak    }

}

Console output:

 Method specific for B was invoked Method specific for B was invoked Exception std::bad_cast thrown. Object is not of type B

A similar version of my_function can be written with pointers instead of references:

void my_function(A* my_a)

{
    if (my_b != nullptr)        my_b->methodSpecificToB();    else        std::cerr << "  Object is not B type" << std::endl;

}

See also

  • Template (C++)
  • Type inference
  • Reflection (computer science)

References

1. ^{{cite web |url=https://docs.oracle.com/cd/E19957-01/806-3571/RTTI.html |title=Runtime Type Identification |year=2000 |author=Sun Microsystems |publisher=Oracle |accessdate=16 April 2015 |website=C++ Programming Guide}}
2. ^{{cite web |author=Bjarne Stroustrup |title=A History of C++: 1979—1991 |url=http://www.stroustrup.com/hopl2.pdf |work= |publisher=Bjarne Stroustrup |date=March 1993 |page=50 |accessdate=2009-05-18}}
3. ^C++ standard (ISO/IEC14882) section 5.2.8 [expr.typeid], 18.5.1 [lib.type.info] -- http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003/documents/c++2003std.pdf
4. ^http://docs.oracle.com/javase/8/docs/api/java/lang/ClassCastException.html

External links

  • dynamic_cast operator at IBM Mac OS X Compilers
  • dynamic_cast operator at MSDN
{{DEFAULTSORT:Run-Time Type Information}}

4 : Articles with example C++ code|C++|Class (computer programming)|Data types

随便看

 

开放百科全书收录14589846条英语、德语、日语等多语种百科知识,基本涵盖了大多数领域的百科知识,是一部内容自由、开放的电子版国际百科全书。

 

Copyright © 2023 OENC.NET All Rights Reserved
京ICP备2021023879号 更新时间:2024/11/12 5:16:37