Jump to content

Информация о типе времени выполнения

В компьютерном программировании информация о типе времени выполнения или идентификация типа времени выполнения ( RTTI ). [1] является особенностью некоторых языков программирования (таких как C++ , [2] Объектный Паскаль и Ада [3] объекта ), который предоставляет информацию о типе данных во время выполнения . Информация о типах времени выполнения может быть доступна для всех типов или только для тех типов, которые ее явно содержат (как в случае с Ada). Информация о типах во время выполнения — это специализация более общей концепции, называемой интроспекцией типов .

В первоначальный проект C++ Бьёрн Страуструп не включил информацию о типах во время выполнения, поскольку считал, что этим механизмом часто злоупотребляют. [4]

В C++ RTTI можно использовать для безопасного приведения типов с помощью dynamic_cast<> оператор и манипулировать информацией о типе во время выполнения с помощью оператора typeid оператор и std::type_info сорт. В Object Pascal RTTI можно использовать для безопасного приведения типов с помощью as оператор, проверьте класс, к которому принадлежит объект, с помощью is оператор и манипулировать информацией о типе во время выполнения с помощью классов, содержащихся в RTTI единица [5] (т.е. классы: TRttiContext , TRttiInstanceType и т. д.). В Ada объекты тегированных типов также хранят тег типа, который позволяет идентифицировать тип этого объекта во время выполнения. in Оператор можно использовать для проверки во время выполнения, принадлежит ли объект определенному типу и может ли он быть безопасно преобразован в него. [6]

RTTI доступен только для полиморфных классов , что означает, что они имеют хотя бы один виртуальный метод . На практике это не является ограничением, поскольку базовые классы должны иметь виртуальный деструктор , позволяющий объектам производных классов выполнять правильную очистку в случае их удаления из базового указателя.

Некоторые компиляторы имеют флаги для отключения RTTI. Использование этих флагов может уменьшить общий размер приложения, что делает их особенно полезными при работе с системами с ограниченным объемом памяти. [7]

C++ — типизированный идентификатор

[ редактировать ]

The typeid зарезервированное слово (ключевое слово) используется для определения класса объекта во время выполнения . Он возвращает ссылку на std::type_info объект, который существует до конца программы. [8] Использование typeid, в неполиморфном контексте, часто предпочтительнее dynamic_cast<class_type> в ситуациях, когда необходима только информация о классе, потому что typeid всегда является процедурой постоянного времени , тогда как dynamic_cast возможно, потребуется пройти решетку вывода классов своего аргумента во время выполнения. [ нужна ссылка ] Некоторые аспекты возвращаемого объекта определяются реализацией, например: std::type_info::name(), и нельзя полагаться на то, что все компиляторы будут согласованными.

Объекты класса std::bad_typeid выбрасываются, когда выражение для typeid является результатом применения унарного оператора * к нулевому указателю . Будет ли выброшено исключение для других аргументов нулевой ссылки, зависит от реализации. Другими словами, чтобы исключение было гарантировано, выражение должно иметь вид typeid(*p) где p любое выражение, приводящее к нулевому указателю.

#include <iostream>
#include <typeinfo>

class Person {
public:
    virtual ~Person() = default;
};

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& p_ref = *p; // Undefined behavior: dereferencing null
    typeid(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.
}

Вывод (точный вывод зависит от системы и компилятора):

Person
Employee
Person*
Employee
Employee

C++ – динамическое_каст и приведение Java

[ редактировать ]

The dynamic_cast Оператор в C++ используется для понижения ссылки или указателя на более конкретный тип в иерархии классов . В отличие от static_cast, цель dynamic_cast должен быть указателем или ссылкой на класс . В отличие от static_cast и приведение типов в стиле C (где проверка типа происходит во время компиляции), проверка безопасности типа выполняется во время выполнения. Если типы несовместимы, исключение будет выдано (при работе со ссылками ) или нулевой указатель будет возвращен (при работе с указателями ).

Приведение типов Java ведет себя аналогично; если приводимый объект на самом деле не является экземпляром целевого типа и не может быть преобразован в него с помощью метода, определенного языком, экземпляр java.lang.ClassCastException будет брошен. [9]

Предположим, некоторая функция принимает объект типа A в качестве аргумента и желает выполнить некоторую дополнительную операцию, если переданный объект является экземпляром B, подкласс A. Это можно сделать с помощью dynamic_cast следующее.

#include <array>
#include <iostream>
#include <memory>
#include <typeinfo>

using namespace std;

class A {
public:
    // Since RTTI is included in the virtual method table there should be at
    // least one virtual function.
    virtual ~A() = default;

    void MethodSpecificToA() {
        cout << "Method specific for A was invoked" << endl;
    }
};

class B: public A {
public:
    void MethodSpecificToB() {
        cout << "Method specific for B was invoked" << endl;
    }
};

void MyFunction(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 (const bad_cast& e) {
        cerr << " Exception " << e.what() << " thrown." << endl;
        cerr << " Object is not of type B" << endl;
    }
}

int main() {
    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 (int i = 0; i < 3; ++i)
        MyFunction(*array_of_a[i]);
}

Вывод консоли:

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

Похожая версия MyFunction можно записать с помощью указателей вместо ссылок :

void MyFunction(A* my_a) {
    B* my_b = dynamic_cast<B*>(my_a);

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

Объектный Паскаль, Делфи

[ редактировать ]

В Object Pascal и Delphi оператор is используется для проверки типа класса во время выполнения. Он проверяет принадлежность объекта к заданному классу, включая классы отдельных предков, присутствующих в дереве иерархии наследования (например, Button1 — это класс TButton , имеющий предков: TWinControl TControl TComponent TPersistent TObject , где последний является предком всех классов). Оператор as используется, когда объект необходимо обрабатывать во время выполнения, как если бы он принадлежал классу-предку.

Модуль RTTI используется для управления информацией о типе объекта во время выполнения. Этот модуль содержит набор классов, которые позволяют: получать информацию о классе объекта и его предках, свойствах, методах и событиях, изменять значения свойств и вызывать методы. В следующем примере показано использование модуля RTTI для получения информации о классе, к которому принадлежит объект, его создания и вызова его метода. В примере предполагается, что класс TSubject объявлен в модуле с именем subjectUnit.

uses
  RTTI, SubjectUnit;

procedure WithoutReflection;
var
  MySubject: TSubject;
begin
  MySubject := TSubject.Create;
  try
    Subject.Hello;
  finally
    Subject.Free;
  end;
end;

procedure WithReflection;
var
  RttiContext: TRttiContext;
  RttiType: TRttiInstanceType;
  Subject: TObject;
begin
  RttiType := RttiContext.FindType('SubjectUnit.TSubject') as TRttiInstanceType;
  Subject := RttiType.GetMethod('Create').Invoke(RttiType.MetaclassType, []).AsObject;
  try
    RttiType.GetMethod('Hello').Invoke(Subject, []);
  finally
    Subject.Free;
  end;
end;

См. также

[ редактировать ]
  1. ^ Сан Микросистемс (2000). «Идентификация типа среды выполнения» . Руководство по программированию на C++ . Оракул . Проверено 16 апреля 2015 г.
  2. ^ «Библиотека языковой поддержки [support.rtti]» . угорь.есть . Проверено 13 июля 2021 г.
  3. ^ «Объектно-ориентированное программирование» . Learn.adacore.com . Проверено 13 июля 2021 г.
  4. ^ Бьерн Страуструп (март 1993 г.). «История C++: 1979–1991» (PDF) . Бьерн Страуструп. п. 50 . Проверено 18 мая 2009 г.
  5. ^ «Работа с RTTI — RAD Studio» . docwiki.embarcadero.com . Проверено 6 июня 2021 г.
  6. ^ Инглиш, Джон (22 февраля 2002 г.). «Глава 15». Ада 95: Искусство объектно-ориентированного программирования . Проверено 13 июля 2021 г.
  7. ^ «Избежание RTTI и поддержка -fno-rtti в Arm Compiler 6» . Разработчик рук . Проверено 13 июля 2021 г.
  8. ^ Стандарт C++ (ISO/IEC14882), раздел 5.2.8 [expr.typeid], 18.5.1 [lib.type.info] - http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003 /документы/С++2003std.pdf
  9. ^ «ClassCastException (платформа Java SE 8)» .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: d57fc8b9cdd159e1ace0736cfdd199bb__1709725380
URL1:https://arc.ask3.ru/arc/aa/d5/bb/d57fc8b9cdd159e1ace0736cfdd199bb.html
Заголовок, (Title) документа по адресу, URL1:
Run-time type information - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)