นี่คือบทสรุปในstatic_cast<>
และdynamic_cast<>
โดยเฉพาะอย่างยิ่งเมื่อพวกเขาเกี่ยวข้องกับตัวชี้ นี่เป็นเพียงบทสรุประดับ 101 มันไม่ครอบคลุมความซับซ้อนทั้งหมด
static_cast <Type *> (ptr)
การดำเนินการนี้จะใช้ตัวชี้ptr
และพยายามส่งไปยังตัวชี้ชนิดType*
อย่างปลอดภัย นักแสดงนี้ทำในเวลารวบรวม มันจะดำเนินการร่ายเมื่อประเภทประเภทที่เกี่ยวข้อง หากประเภทไม่เกี่ยวข้องคุณจะได้รับข้อผิดพลาดของคอมไพเลอร์ ตัวอย่างเช่น:
class B {};
class D : public B {};
class X {};
int main()
{
D* d = new D;
B* b = static_cast<B*>(d); // this works
X* x = static_cast<X*>(d); // ERROR - Won't compile
return 0;
}
dynamic_cast <Type *> (ptr)
สิ่งนี้จะพยายามนำตัวชี้เข้ามาอีกครั้งptr
และโยนไปยังตัวชี้ชนิดType*
อย่างปลอดภัย แต่นักแสดงนี้จะถูกสั่งการตอนรันไทม์ไม่ใช่เวลารวบรวม เนื่องจากนี่เป็นระยะเวลาทำงานจึงมีประโยชน์โดยเฉพาะเมื่อรวมกับคลาส polymorphic ในความเป็นจริงในกรณีใบรับรองคลาสจะต้องมีความหลากหลายเพื่อให้นักแสดงถูกกฎหมาย
การร่ายสามารถไปในหนึ่งในสองทิศทาง: จากฐานสู่มา (B2D) หรือจากมาถึงฐาน (D2B) มันง่ายพอที่จะดูว่า D2B จะทำงานอย่างไรในการรันไทม์ อาจptr
มาจากType
หรือไม่ก็ได้ ในกรณีของ D2B dynamic_cast <> s กฎนั้นง่าย คุณสามารถพยายามที่จะโยนทุกอย่างเพื่อสิ่งอื่นใดและถ้าptr
ในความเป็นจริงที่ได้มาจากType
คุณจะได้รับกลับมาชี้จากType*
dynamic_cast
มิฉะนั้นคุณจะได้ตัวชี้ NULL
แต่บรรยากาศของ B2D นั้นซับซ้อนกว่าเล็กน้อย พิจารณารหัสต่อไปนี้:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void DoIt() = 0; // pure virtual
virtual ~Base() {};
};
class Foo : public Base
{
public:
virtual void DoIt() { cout << "Foo"; };
void FooIt() { cout << "Fooing It..."; }
};
class Bar : public Base
{
public :
virtual void DoIt() { cout << "Bar"; }
void BarIt() { cout << "baring It..."; }
};
Base* CreateRandom()
{
if( (rand()%2) == 0 )
return new Foo;
else
return new Bar;
}
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = (Bar*)base;
bar->BarIt();
}
return 0;
}
main()
ไม่สามารถบอกได้ว่าวัตถุชนิดใดCreateRandom()
จะกลับมาดังนั้นการเลือกแบบ C Bar* bar = (Bar*)base;
จึงไม่ปลอดภัย คุณจะแก้ไขสิ่งนี้ได้อย่างไร วิธีการหนึ่งที่จะเพิ่มฟังก์ชั่นเช่นบูลAreYouABar() const = 0;
ไปชั้นฐานและกลับtrue
จากBar
และจากfalse
Foo
แต่มีวิธีอื่น: ใช้dynamic_cast<>
:
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = dynamic_cast<Bar*>(base);
Foo* foo = dynamic_cast<Foo*>(base);
if( bar )
bar->BarIt();
if( foo )
foo->FooIt();
}
return 0;
}
casts รันที่รันไทม์และทำงานโดยการเคียวรีออบเจ็กต์ (ไม่ต้องกังวลเกี่ยวกับวิธีการตอนนี้) โดยถามว่าเป็นประเภทที่เรากำลังมองหาหรือไม่ ถ้าเป็นก็จะdynamic_cast<Type*>
ส่งคืนพอยน์เตอร์ มิฉะนั้นจะส่งคืน NULL
ในการสั่งซื้อสำหรับฐานที่จะได้มาจากการหล่อการทำงานโดยใช้dynamic_cast<>
ฐานฟูและบาร์จะต้องเป็นสิ่งที่เรียกมาตรฐานประเภท polymorphic เพื่อให้เป็น polymorphic type คลาสของคุณต้องมีอย่างน้อยหนึ่งvirtual
ฟังก์ชัน หากคลาสของคุณไม่ใช่ประเภท polymorphic การใช้งานพื้นฐานจากที่ได้มาdynamic_cast
จะไม่รวบรวม ตัวอย่าง:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
การเพิ่มฟังก์ชั่นเสมือนลงในฐานเช่น dtor เสมือนจะทำให้ทั้งประเภทฐานและ Der polymorphic:
class Base
{
public:
virtual ~Base(){};
};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // OK
return 0;
}
dynamic_cast<>
ทำงานเบื้องหลัง (หรือวิธีการทำงานของ C ++) หนังสือดี ๆ (นั่นเป็นเรื่องง่ายที่จะอ่านสำหรับเทคนิคดังนั้น) เป็น Lippman "Inside the C ++ Object Model" นอกจากนี้หนังสือ "การออกแบบและวิวัฒนาการของ C ++" และ "ภาษาการเขียนโปรแกรม C ++" ของ Stroustrup ยังเป็นแหล่งข้อมูลที่ดี แต่หนังสือของ Lippman นั้นอุทิศให้กับการทำงานของ C ++ 'เบื้องหลัง'