Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Run-time type information

From Wikipedia, the free encyclopedia
(Redirected fromDynamic cast)
Programming language feature that exposes information about an object's data type at runtime

Incomputer programming,run-time type information orrun-time type identification (RTTI)[1] is a feature of some programming languages (such asC++,[2]Object Pascal, andAda[3]) that exposes information about an object'sdata type atruntime. Run-time type information may be available for all types or only to types that explicitly have it (as is the case with Ada). Run-time type information is a specialization of a more general concept calledtype introspection.

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

Overview

[edit]

In C++, RTTI can be used to do safetypecasts using thedynamic_cast<> operator, and to manipulate type information at runtime using thetypeid operator andstd::type_info class. In Object Pascal, RTTI can be used to perform safe type casts with theas operator, test the class to which an object belongs with theis operator, and manipulate type information at run time with classes contained in theRTTI unit[5] (i.e. classes:TRttiContext,TRttiInstanceType, etc.). In Ada, objects of tagged types also store a type tag, which permits the identification of the type of these object at runtime. Thein operator can be used to test, at runtime, if an object is of a specific type and may be safely converted to it.[6]

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

Some compilers have flags to disable RTTI. Using these flags may reduce the overall size of the application, making them especially useful when targeting systems with a limited amount of memory.[7]

C++typeid operator

[edit]

Thetypeidreserved word (keyword) is used to determine theclass of anobject at runtime. It returns areference tostd::type_info object, which exists until the end of the program.[8] The use oftypeid, in a non-polymorphic context, is often preferred overdynamic_cast<ClassType> in situations where just the class information is needed, becausetypeid is always aconstant-time procedure, whereasdynamic_cast may need to traverse the class derivation lattice of its argument at runtime.[citation needed] Some aspects of the returned object are implementation-defined, such asstd::type_info::name(), and cannot be relied on across compilers to be consistent.

Objects of classstd::bad_typeid are thrown when the expression fortypeid() is the result of applying the unary* operator on anull 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 formtypeid(*p) wherep is any expression resulting in a null pointer.

Thetypeid operator, if used in a context wherestd::type_info is not visible, is ill-informed. It is defined in header<typeinfo> (ormodulestd).

Example

[edit]
importstd;usingstd::bad_typeid;usingstd::type_info;classPerson{public:virtual~Person()=default;};classEmployee:publicPerson{// ...};intmain(){Personperson;Employeeemployee;Person*ptr=&employee;Person&ref=employee;type_infopersonType=typeid(person);type_infoemployeeType=typeid(employee);type_infoptrType=typeid(ptr);type_inforefType=typeid(ref);// The string returned by std::type_info::name() is implementation-defined.std::println("{}",personType.name());// Person (statically known at compile-time).std::println("{}",employeeType.name());// Employee (statically known at compile-time).std::println("{}",ptrType.name());// Person* (statically known at compile-time).std::println("{}",refType.name());// Employee// (looked up dynamically at run-time// because it is the dereference of a// pointer to a polymorphic class).std::println("{}",typeid(ref).name());// Employee (references can also be polymorphic)Person*p=nullptr;try{typeid(*p);// Not undefined behavior; throws std::bad_typeid.}catch(constbad_typeid&e){std::println(stderr,"Exception caught: {}",e.what());}Person&ref2=*p;// Undefined behavior: dereferencing null// Does not meet requirements to throw std::bad_typeid// because the expression for typeid is not the result// of applying the unary * operator.type_inforef2Type=typeid(ref2);}

Output (exact output varies by system andcompiler):

PersonEmployeePerson*EmployeeEmployee

C++dynamic_cast and Java cast

[edit]

Thedynamic_cast operator inC++ is used fordowncasting a reference or pointer to a more specific type in theclass hierarchy. Unlike thestatic_cast, the target of thedynamic_cast must be apointer orreference toclass. Unlikestatic_cast andC-style typecast (where type check occurs while compiling), atype safety check is performed at runtime. If the types are not compatible, anexception will be thrown (when dealing withreferences) or anull pointer will be returned (when dealing withpointers).

AJava 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 ofjava.lang.ClassCastException will be thrown.[9]

Example

[edit]

Suppose somefunction takes anobject of typeBase as its argument, and wishes to perform some additional operation if the object passed is an instance ofDerived, asubclass ofBase. This can be done usingdynamic_cast as follows.

importstd;usingstd::array;usingstd::bad_cast;usingstd::unique_ptr;classBase{private:voidspecificToBase()const{std::println("Method specific for Base was invoked");}public:// Since RTTI is included in the virtual method table there should be at// least one virtual function.virtual~Base()=default;};classDerived:publicBase{public:voidspecificToDerived()const{std::println("Method specific for B was invoked");}};voidmyFunction(Base&base){try{// Cast will be successful only for B type objects.Derived&derived=dynamic_cast<Derived&>(base);derived.specificToDerived();}catch(constbad_cast&e){std::println(stderr,"Exception {} thrown.",e.what());std::println("Object is not of type Derived");}}intmain(intargc,char*argv[]){// Array of pointers to base class A.array<unique_ptr<Base>,3>arrayOfBase={std::make_unique<Derived>();// Pointer to Derived object.std::make_unique<Derived>();// Pointer to Derived object.std::make_unique<Base>();// Pointer to Base object.}for(Baseb:arrayOfBase){myFunction(*b);}return0;}

Console output:

Method specific for Derived was invokedMethod specific for Derived was invokedException std::bad_cast thrown.Object is not of type Derived

A similar version ofmyFunction can be written withpointers instead ofreferences:

voidmyFunction(Base*base){Derived*derived=dynamic_cast<Derived*>(base);if(derived){derived->specificToDerived();}else{std::println(stderr,"Object is not Derived type");}}

Object Pascal, Delphi

[edit]

In Object Pascal andDelphi, the operatoris is used to check the type of a class at runtime. It tests the belonging of an object to a given class, including classes of individual ancestors present in the inheritance hierarchy tree (e.g.Button1 is aTButton class that has ancestors:TWinControlTControlTComponentTPersistentTObject, where the latter is the ancestor of all classes). The operatoras is used when an object needs to be treated at run time as if it belonged to an ancestor class.

The RTTI unit is used to manipulate object type information at run time. This unit contains a set of classes that allow you to: get information about an object's class and its ancestors, properties, methods and events, change property values and call methods. The following example shows the use of the RTTI module to obtain information about the class to which an object belongs, creating it, and to call its method. The example assumes that the TSubject class has been declared in a unit named SubjectUnit.

usesRTTI,SubjectUnit;procedureWithoutReflection;varMySubject:TSubject;beginMySubject:=TSubject.Create;trySubject.Hello;finallySubject.Free;end;end;procedureWithReflection;varRttiContext:TRttiContext;RttiType:TRttiInstanceType;Subject:TObject;beginRttiType:=RttiContext.FindType('SubjectUnit.TSubject')asTRttiInstanceType;Subject:=RttiType.GetMethod('Create').Invoke(RttiType.MetaclassType,[]).AsObject;tryRttiType.GetMethod('Hello').Invoke(Subject,[]);finallySubject.Free;end;end;

See also

[edit]

References

[edit]
  1. ^Sun Microsystems (2000)."Runtime Type Identification".C++ Programming Guide. Oracle. Retrieved16 April 2015.
  2. ^"Language support library [support.rtti]".eel.is. Retrieved2021-07-13.
  3. ^"Object-oriented programming".learn.adacore.com. Retrieved2021-07-13.
  4. ^Bjarne Stroustrup (March 1993)."A History of C++: 1979—1991"(PDF). Bjarne Stroustrup. p. 50. Retrieved2009-05-18.
  5. ^"Working with RTTI - RAD Studio".docwiki.embarcadero.com. Retrieved2021-06-06.
  6. ^English, John (2002-02-22). "Chapter 15".Ada 95: The Craft of Object-Oriented Programming. Retrieved2021-07-13.
  7. ^"Avoiding RTTI, and support for -fno-rtti in Arm Compiler 6".Arm Developer. Retrieved2021-07-13.
  8. ^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
  9. ^"ClassCastException (Java Platform SE 8)".

External links

[edit]
Retrieved from "https://en.wikipedia.org/w/index.php?title=Run-time_type_information&oldid=1319943010#dynamic_cast"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp