Ç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 typeid
operatör ve std::type_info
sınıfı kullanarak çalışma zamanında tür bilgilerini değiştirmek için kullanılabilir . Object Pascal'da RTTI, as
operatörle güvenli tip yayınları gerçekleştirmek , bir nesnenin ait olduğu sınıfı operatörle test etmek is
ve RTTI
birimde 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. in
Bir 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_info
program sonuna kadar var olan nesne. Kullanımı typeid
olmayan 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>
typeid
dynamic_cast
std::type_info::name()
std::bad_typeid
for ifadesi typeid
bir 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_cast
Operatö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_cast
bir olmalıdır işaretçi ya da referans ile sınıfı . static_cast
ve 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.ClassCastException
atılır.
Misal
Bazı varsayalım fonksiyonu bir alır nesne Çeşidi A
bağımsız değişken olarak ve geçirilen nesne bir örneği ise, bazı ek işlemi gerçekleştirmek isteyen B
bir, alt-sınıfına ait A
. Bu, dynamic_cast
aş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: TWinControl → TControl → TComponent → TPersistent → TObject , 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;