Çalışma zamanı türü bilgisi - Run-time type information

Bilgisayar programlama, In zamanı tür bilgi veya çalışma zamanı tip tanımlaması ( RTTI ) bazı programlama dilleri bir özelliğidir (örneğin C ++ , Object Pascal ve Ada ) bir nesnenin hakkında böyle İFŞA bilgi veri türü de çalışma zamanı . Çalışma zamanı türü bilgisi, tüm türler için veya yalnızca (Ada'da olduğu gibi) açıkça sahip olan türler için mevcut olabilir. Çalışma zamanı türü bilgisi, tür iç gözlemi adı verilen daha genel bir kavramın uzmanlaşmasıdır .

Orijinal C++ tasarımında, Bjarne Stroustrup , bu mekanizmanın sıklıkla yanlış kullanıldığını düşündüğü için çalışma zamanı türü bilgilerini içermiyordu.

genel bakış

C++'da RTTI , operatörü kullanarak güvenli tip yayınları yapmak dynamic_cast<>ve typeidoperatör ve std::type_infosınıfı kullanarak çalışma zamanında tür bilgilerini değiştirmek için kullanılabilir . Object Pascal'da RTTI, asoperatörle güvenli tip yayınları gerçekleştirmek , bir nesnenin ait olduğu sınıfı operatörle test etmek isve RTTIbirimde bulunan sınıflarla çalışma zamanında tip bilgilerini değiştirmek için kullanılabilir (yani sınıflar: TRttiContext , TRttiInstanceType , vb.). Ada'da, etiketli türlerdeki nesneler, çalışma zamanında bu nesnelerin türünün tanımlanmasına izin veren bir tür etiketi de depolar. inBir nesnenin belirli bir tiptedir ve güvenli bir şekilde buna dönüştürülebilen, operatör, zamanında test etmek için de kullanılabilir.

RTTI yalnızca polimorfik olan sınıflar için kullanılabilir , bu da onların en az bir sanal yöntemi olduğu anlamına gelir . Pratikte bu bir sınırlama değildir, çünkü temel sınıfların , türetilmiş sınıfların nesnelerinin bir temel işaretçiden silinmeleri durumunda uygun temizleme gerçekleştirmesine izin vermek için sanal bir yıkıcıya sahip olması gerekir .

Bazı derleyiciler, RTTI'yi devre dışı bırakmak için bayraklara sahiptir. Bu bayrakların kullanılması, uygulamanın genel boyutunu azaltabilir ve bu da onları özellikle sınırlı miktarda belleğe sahip sistemleri hedeflerken kullanışlı hale getirir.

C++ – tip kimliği

typeid Anahtar kelime belirlemek için kullanılan sınıf bir bir nesneye de çalışma zamanında . Bir döner referans için std::type_infoprogram sonuna kadar var olan nesne. Kullanımı typeidolmayan bir polimorfik bağlamda, sık sık daha çok tercih edilir , çünkü, sadece sınıf bilgileri gerektiği hallerde de bir her zaman sabit zaman prosedürü ise zamanında argüman sınıf türetme kafes hareket etmesi gerekli olabilir. Döndürülen nesnenin bazı yönleri, gibi uygulama tarafından tanımlanmıştır ve tutarlı olması için derleyiciler arasında güvenilemez. dynamic_cast<class_type>typeiddynamic_caststd::type_info::name()

std::bad_typeidfor ifadesi typeidbir boş göstericiye unary * operatörünün uygulanmasının sonucu olduğunda, sınıfın nesneleri atılır . Diğer boş başvuru argümanları için bir istisna atılıp atılmadığı uygulamaya bağlıdır. Özel garanti edilmesi için, diğer bir deyişle, ekspresyon şeklinde olmak zorundadır bir boş gösterici sonuçlanan herhangi bir ifadesidir. typeid(*p)p

Misal

#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.
}

Çıktı (tam çıktı sisteme ve derleyiciye göre değişir):

Person
Employee
Person*
Employee
Employee

C++ – dynamic_cast ve Java cast

dynamic_castOperatör C ++ için kullanılan downcasting içinde daha özel bir türüne açıklamayı veya işaretçi sınıf hiyerarşisi . Farklı olarak static_cast, hedef dynamic_castbir olmalıdır işaretçi ya da referans ile sınıfı . static_castve C tarzı typecast'in (derleme sırasında tür kontrolünün yapıldığı yer) aksine , çalışma zamanında bir tür güvenlik kontrolü gerçekleştirilir . Türler uyumlu değilse, bir istisna atılır ( referanslarla ilgilenirken ) veya bir boş gösterici döndürülür ( işaretçilerle uğraşırken ).

Bir Java benzer davranır typecasting; dönüştürülmekte olan nesne aslında hedef türün bir örneği değilse ve dil tanımlı bir yöntemle bir nesneye dönüştürülemiyorsa, bir örneği java.lang.ClassCastExceptionatılır.

Misal

Bazı varsayalım fonksiyonu bir alır nesne Çeşidi Abağımsız değişken olarak ve geçirilen nesne bir örneği ise, bazı ek işlemi gerçekleştirmek isteyen Bbir, alt-sınıfına ait A. Bu, dynamic_castaşağıdaki şekilde kullanılarak gerçekleştirilebilir .

#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]);
}

Konsol çıkışı:

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

Benzer bir sürümü referanslar yerine işaretçilerleMyFunction yazılabilir :

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;
}

Delphi / Nesne Pascal

Object Pascal'da operatör is, çalışma zamanında bir sınıfın türünü kontrol etmek için kullanılır . Kalıtım hiyerarşi ağacında bulunan bireysel ataların sınıfları da dahil olmak üzere bir nesnenin belirli bir sınıfa ait olup olmadığını test eder (örneğin, Button1 , ataları olan bir TButton sınıfıdır: TWinControlTControlTComponentTPersistentTObject , burada ikincisi atadır tüm sınıflar). Operatör as, bir nesnenin çalışma zamanında bir ata sınıfına aitmiş gibi ele alınması gerektiğinde kullanılır.

RTTI birimi, çalışma zamanında nesne tipi bilgilerini işlemek için kullanılır. Bu birim, şunları yapmanıza izin veren bir dizi sınıf içerir: bir nesnenin sınıfı ve ataları, özellikleri, yöntemleri ve olayları hakkında bilgi edinme, özellik değerlerini değiştirme ve yöntemleri çağırma. Aşağıdaki örnek, bir nesnenin ait olduğu sınıf hakkında bilgi almak, onu oluşturmak ve yöntemini çağırmak için RTTI modülünün kullanımını gösterir. Örnek, TSubject sınıfının SubjectUnit adlı bir birimde bildirildiğini varsayar.

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;

Ayrıca bakınız

Referanslar

Dış bağlantılar