dynamic_cast İşleci
İşleneni expression
türünde type-id
bir nesneye dönüştürür.
Sözdizimi
dynamic_cast < type-id > ( expression )
Açıklamalar
, type-id
önceden tanımlanmış bir sınıf türüne veya "void işaretçisine" bir işaretçi veya başvuru olmalıdır. türü expression
işaretçi ise type-id
işaretçi veya başvuru ise type-id
l değeri olmalıdır.
Statik ve dinamik atama dönüştürmeleri arasındaki farkın ve bunların ne zaman kullanılmasının uygun olduğunu gösteren bir açıklama için bkz . static_cast .
Yönetilen kodda davranışında iki hataya neden olan dynamic_cast
değişiklik vardır:
dynamic_cast
kutulanmış bir sabit kutusunun temel türüne ilişkin bir işaretçi çalışma zamanında başarısız olur ve dönüştürülen işaretçi yerine 0 döndürür.dynamic_cast
artık bir değer türünün iç işaretçisi olduğundatype-id
özel durum oluşturmaz; bunun yerine atama çalışma zamanında başarısız olur. Atama, atmak yerine 0 işaretçisi değerini döndürür.
açık olmayan erişilebilir doğrudan veya dolaylı temel sınıfına expression
yönelik bir işaretçiysetype-id
, türün type-id
benzersiz alt nesnesine yönelik bir işaretçi sonuç olur. Örnek:
// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };
void f(D* pd) {
C* pc = dynamic_cast<C*>(pd); // ok: C is a direct base class
// pc points to C subobject of pd
B* pb = dynamic_cast<B*>(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
}
Bir işaretçiyi türetilmiş bir sınıftan türetildiği sınıfa bir sınıf hiyerarşisi yukarı taşıması nedeniyle bu dönüştürme türüne "yukarı yayın" adı verilir. Yukarı yayın örtük bir dönüştürmedir.
geçersizse type-id
*, gerçek türünü expression
belirlemek için bir çalışma zamanı denetimi yapılır. Sonuç, tarafından expression
işaret edilen tam nesnenin işaretçisidir. Örnek:
// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
void f() {
A* pa = new A;
B* pb = new B;
void* pv = dynamic_cast<void*>(pa);
// pv now points to an object of type A
pv = dynamic_cast<void*>(pb);
// pv now points to an object of type B
}
değilse type-id
void*
, tarafından işaret edilen nesnenin tarafından işaret edilen türe dönüştürülip dönüştürülemediğini görmek için expression
type-id
bir çalışma zamanı denetimi yapılır.
türü expression
türünün temel sınıfıysatype-id
, türünün tam bir nesnesine type-id
işaret olup olmadığını expression
görmek için bir çalışma zamanı denetimi yapılır. Bu doğruysa, sonuç türündeki tam bir nesnenin işaretçisidir type-id
. Örnek:
// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};
void f() {
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
}
Bir işaretçiyi bir sınıf hiyerarşisinin aşağısına, belirli bir sınıftan türetilen bir sınıfa taşıması nedeniyle bu tür dönüştürmeye "aşağı yayın" adı verilir.
Birden çok devralma durumunda belirsizlik olasılıkları ortaya çıkmıştır. Aşağıdaki şekilde gösterilen sınıf hiyerarşisini göz önünde bulundurun.
CLR türleri için, dynamic_cast
dönüştürme örtük olarak gerçekleştirilebiliyorsa işlem yapılmaz veya dinamik denetim gerçekleştiren ve dönüştürme başarısız olursa döndüren nullptr
bir MSIL isinst
yönergesi elde eder.
Aşağıdaki örnek, bir sınıfın belirli türde bir örnek olup olmadığını belirlemek için kullanır dynamic_cast
:
// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;
void PrintObjectType( Object^o ) {
if( dynamic_cast<String^>(o) )
Console::WriteLine("Object is a String");
else if( dynamic_cast<int^>(o) )
Console::WriteLine("Object is an int");
}
int main() {
Object^o1 = "hello";
Object^o2 = 10;
PrintObjectType(o1);
PrintObjectType(o2);
}
Diyagramda, temel bir D sınıfı olan B'nin temel sınıfı olarak A ile bir sınıf hiyerarşisi gösterilir. A aynı zamanda C için bir temel sınıftır ve bu da D için bir temel sınıftır. D Sınıfı hem B hem de C'den devralır.
Türünde D
bir nesnenin işaretçisi veya C
öğesine B
güvenli bir şekilde atanabilir. Ancak, bir A
nesneye işaret edecek şekilde yayınlanırsaD
, hangi örneği A
sonuçlanır? Bu, belirsiz bir atama hatasına neden olur. Bu sorunu çözmek için iki kesin atama gerçekleştirebilirsiniz. Örnek:
// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A {virtual void f();};
class D : public B, public C {virtual void f();};
void f() {
D* pd = new D;
A* pa = dynamic_cast<A*>(pd); // C4540, ambiguous cast fails at runtime
B* pb = dynamic_cast<B*>(pd); // first cast to B
A* pa2 = dynamic_cast<A*>(pb); // ok: unambiguous
}
Sanal temel sınıfları kullandığınızda daha fazla belirsizlik ortaya eklenebilir. Aşağıdaki şekilde gösterilen sınıf hiyerarşisini göz önünde bulundurun.
Diyagramda A, B, C, D ve E sınıfları şu şekilde düzenlenmiştir: Sınıf A, B'nin temel sınıfıdır. C ve E sınıflarının her biri B'den türetilir. E Sınıfı da A sınıfından devralan B sınıfından devralan D sınıfından devralır.
Sanal temel sınıfları gösteren sınıf hiyerarşisi
Bu hiyerarşide bir A
sanal temel sınıftır. Sınıfın E
bir örneği ve alt nesneye A
yönelik bir işaretçi verilip belirsizlik dynamic_cast
nedeniyle başarısız olması için B
bir işaretçi. Doğru nesneye ulaşmak için önce tam E
nesneye geri döndürmeniz, ardından hiyerarşiyi kesin olmayan bir şekilde yedeklemeniz B
gerekir.
Aşağıdaki şekilde gösterilen sınıf hiyerarşisini göz önünde bulundurun.
Diyagramda A, B, C, D ve E sınıfları şu şekilde düzenlenmiş şekilde gösterilir: B Sınıfı A Sınıfından türetilir. C Sınıfı A sınıfından türetilir. D sınıfı B sınıfından türetilir. E Sınıfı, A sınıfından türetilen C sınıfından türetilir. Bu durumda, yinelenen temel sınıf, doğrudan veya dolaylı olarak diğer tüm sınıflar tarafından devralınan A sınıfıdır. A sınıfı doğrudan B ve C sınıfları tarafından, dolaylı olarak B sınıfı aracılığıyla D sınıfı tarafından ve C sınıfı aracılığıyla dolaylı olarak E sınıfı tarafından ve B sınıfı aracılığıyla dolaylı olarak D sınıfı tarafından devralınır.
Yinelenen temel sınıfları gösteren sınıf hiyerarşisi
Türünde E
bir nesne ve alt nesne işaretçisi D
verilip alt nesneden D
en soldaki A
alt nesneye gitmek için üç dönüştürme yapılabilir. İşaretçiden bir dynamic_cast
E
işaretçiye dönüştürme, sonra 'dan E
B
D
öğesine dönüştürme (dynamic_cast
veya örtük dönüştürme) ve son olarak 'dan B
'a A
örtük dönüştürme gerçekleştirebilirsiniz. Örnek:
// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};
void f(D* pd) {
E* pe = dynamic_cast<E*>(pd);
B* pb = pe; // upcast, implicit conversion
A* pa = pb; // upcast, implicit conversion
}
işleci dynamic_cast
bir "çapraz atama" gerçekleştirmek için de kullanılabilir. Aynı sınıf hiyerarşisini kullanarak, tam nesne türünde E
olduğu sürece, örneğin, alt nesneden B
alt nesneye D
bir işaretçi oluşturmak mümkündür.
Çapraz atamaları göz önünde bulundurarak, bir işaretçiden D
en soldaki A
alt nesneye doğru bir işaretçiye dönüştürmeyi yalnızca iki adımda yapmak mümkündür. 'den D
öğesine B
çapraz atama ve ardından 'den B
A
öğesine örtük dönüştürme gerçekleştirebilirsiniz. Örnek:
// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};
void f(D* pd) {
B* pb = dynamic_cast<B*>(pd); // cross cast
A* pa = pb; // upcast, implicit conversion
}
Null işaretçi değeri, tarafından dynamic_cast
hedef türün null işaretçi değerine dönüştürülür.
kullandığınızda dynamic_cast < type-id > ( expression )
, expression
türüne type-id
güvenli bir şekilde dönüştürülemiyorsa, çalışma zamanı denetimi atamanın başarısız olmasına neden olur. Örnek:
// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
void f() {
A* pa = new A;
B* pb = dynamic_cast<B*>(pa); // fails at runtime, not safe;
// B not derived from A
}
İşaretçi türüne atanamayan bir değeri null işaretçidir. Başvuru türüne başarısız olan bir atama, bad_cast Özel Durumu oluşturur. Geçerli bir nesneye işaret etmiyor veya bu nesneye başvurmuyorsa expression
, bir __non_rtti_object
özel durum oluşturulur.
Özel durumun açıklaması için bkz. typeid.__non_rtti_object
Örnek
Aşağıdaki örnek, bir nesne (yapı C) için temel sınıf (yapı A) işaretçisini oluşturur. Bunun yanı sıra sanal işlevler olduğu gerçeği, çalışma zamanı polimorfizmini etkinleştirir.
Örnek, hiyerarşideki sanal olmayan bir işlevi de çağırır.
// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>
struct A {
virtual void test() {
printf_s("in A\n");
}
};
struct B : A {
virtual void test() {
printf_s("in B\n");
}
void test2() {
printf_s("test2 in B\n");
}
};
struct C : B {
virtual void test() {
printf_s("in C\n");
}
void test2() {
printf_s("test2 in C\n");
}
};
void Globaltest(A& a) {
try {
C &c = dynamic_cast<C&>(a);
printf_s("in GlobalTest\n");
}
catch(std::bad_cast) {
printf_s("Can't cast to C\n");
}
}
int main() {
A *pa = new C;
A *pa2 = new B;
pa->test();
B * pb = dynamic_cast<B *>(pa);
if (pb)
pb->test2();
C * pc = dynamic_cast<C *>(pa2);
if (pc)
pc->test2();
C ConStack;
Globaltest(ConStack);
// fails because B knows nothing about C
B BonStack;
Globaltest(BonStack);
}
in C
test2 in B
in GlobalTest
Can't cast to C
Ayrıca bkz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin