Run-time type information

Last updated

In computer programming, run-time type information or run-time type identification (RTTI) [1] is a feature of some programming languages (such as C++, [2] Object Pascal, and Ada [3] ) that exposes information about an object's data type at runtime. 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 called type introspection.

Contents

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

Overview

In C++, RTTI can be used to do safe typecasts using the dynamic_cast<> operator, and to manipulate type information at runtime using the typeid operator and std::type_info class. In Object Pascal, RTTI can be used to perform safe type casts with the as operator, test the class to which an object belongs with the is operator, and manipulate type information at run time with classes contained in the RTTI 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. The in 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 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.

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

The typeid reserved word (keyword) is used to determine the class of an object at runtime. It returns a reference to std::type_info object, which exists until the end of the program. [8] 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 ] 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

#include<iostream>#include<typeinfo>classPerson{public:virtual~Person()=default;};classEmployee:publicPerson{};intmain(){Personperson;Employeeemployee;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&p_ref=*p;// Undefined behavior: dereferencing nulltypeid(p_ref);// 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

C++ – 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 occurs while compiling), 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. [9]

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 done using dynamic_cast as follows.

#include<array>#include<iostream>#include<memory>#include<typeinfo>usingnamespacestd;classA{public:// Since RTTI is included in the virtual method table there should be at// least one virtual function.virtual~A()=default;voidMethodSpecificToA(){cout<<"Method specific for A was invoked"<<endl;}};classB:publicA{public:voidMethodSpecificToB(){cout<<"Method specific for B was invoked"<<endl;}};voidMyFunction(A&my_a){try{// Cast will be successful only for B type objects.B&my_b=dynamic_cast<B&>(my_a);my_b.MethodSpecificToB();}catch(constbad_cast&e){cerr<<" Exception "<<e.what()<<" thrown."<<endl;cerr<<" Object is not of type B"<<endl;}}intmain(){array<unique_ptr<A>,3>array_of_a;// Array of pointers to base class A.array_of_a[0]=make_unique<B>();// Pointer to B object.array_of_a[1]=make_unique<B>();// Pointer to B object.array_of_a[2]=make_unique<A>();// Pointer to A object.for(inti=0;i<3;++i)MyFunction(*array_of_a[i]);}

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 MyFunction can be written with pointers instead of references:

voidMyFunction(A*my_a){B*my_b=dynamic_cast<B*>(my_a);if(my_b!=nullptr)my_b->methodSpecificToB();elsestd::cerr<<"  Object is not B type"<<std::endl;}

Object Pascal, Delphi

In Object Pascal and Delphi, the operator is 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 a TButton class that has ancestors: TWinControlTControlTComponentTPersistentTObject, where the latter is the ancestor of all classes). The operator as 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

Related Research Articles

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other instances of the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.

Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run-time (dynamic) type or, in the more general case, some other attribute of more than one of its arguments. This is a generalization of single-dispatch polymorphism where a function or method call is dynamically dispatched based on the derived type of the object on which the method has been called. Multiple dispatch routes the dynamic dispatch to the implementing function or method using the combined characteristics of one or more arguments.

Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates can include compile-time constants, data structures, and complete functions. The use of templates can be thought of as compile-time polymorphism. The technique is used by a number of languages, the best-known being C++, but also Curl, D, Nim, and XL.

A method in object-oriented programming (OOP) is a procedure associated with an object, and generally also a message. An object consists of state data and behavior; these compose an interface, which specifies how the object may be used. A method is a behavior of an object parametrized by a user.

<span class="mw-page-title-main">D (programming language)</span> Multi-paradigm system programming language

D, also known as dlang, is a multi-paradigm system programming language created by Walter Bright at Digital Mars and released in 2001. Andrei Alexandrescu joined the design and development effort in 2007. Though it originated as a re-engineering of C++, D is now a very different language drawing inspiration from other high-level programming languages, notably Java, Python, Ruby, C#, and Eiffel.

In object-oriented programming such as is often used in C++ and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method that is dispatched dynamically. Virtual functions are an important part of (runtime) polymorphism in object-oriented programming (OOP). They allow for the execution of target functions that were not precisely identified at compile time.

In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.

<span class="mw-page-title-main">Pointer (computer programming)</span> Object which stores memory addresses in a computer program

In computer science, a pointer is an object in many programming languages that stores a memory address. This can be that of another value located in computer memory, or in some cases, that of memory-mapped computer hardware. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book's index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number and reading the text found on that page. The actual format and content of a pointer variable is dependent on the underlying computer architecture.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. In some languages, particularly C++, function objects are often called functors.

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer referencing executable code, rather than data. Dereferencing the function pointer yields the referenced function, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invoked indirectly through a variable instead of directly through a fixed identifier or address.

In the C++ programming language, a copy constructor is a special constructor for creating a new object as a copy of an existing object. Copy constructors are the standard way of copying objects in C++, as opposed to cloning, and have C++-specific nuances.

In computer science, type safety and type soundness are the extent to which a programming language discourages or prevents type errors. Type safety is sometimes alternatively considered to be a property of facilities of a computer language; that is, some facilities are type-safe and their usage will not result in type errors, while other facilities in the same language may be type-unsafe and a program using them may encounter type errors. The behaviors classified as type errors by a given programming language are usually those that result from attempts to perform operations on values that are not of the appropriate data type, e.g., adding a string to an integer when there's no definition on how to handle this case. This classification is partly based on opinion.

In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The definition of a reference in C++ is such that it does not need to exist. It can be implemented as a new name for an existing object.

C++/CLI is a variant of the C++ programming language, modified for Common Language Infrastructure. It has been part of Visual Studio 2005 and later, and provides interoperability with other .NET languages such as C#. Microsoft created C++/CLI to supersede Managed Extensions for C++. In December 2005, Ecma International published C++/CLI specifications as the ECMA-372 standard.

A class in C++ is a user-defined type or data structure declared with any of the keywords class, struct or union that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class declared with the keyword class is private. The private members are not accessible outside the class; they can be accessed only through member functions of the class. The public members form an interface to the class and are accessible outside the class.

The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. More generally it is known as F-bound polymorphism, and it is a form of F-bounded quantification.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

In the C++ programming language, placement syntax allows programmers to explicitly specify the memory management of individual objects — i.e. their "placement" in memory. Normally, when an object is created dynamically, an allocation function is invoked in such a way that it will both allocate memory for the object, and initialize the object within the newly allocated memory. The placement syntax allows the programmer to supply additional arguments to the allocation function. A common use is to supply a pointer to a suitable region of storage where the object can be initialized, thus separating memory allocation from object construction.

In computer programming, variadic templates are templates that take a variable number of arguments.

References

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