Đây là một danh sách static_cast<>
và dynamic_cast<>
đặc biệt là khi chúng liên quan đến con trỏ. Đây chỉ là một danh sách cấp 101, nó không bao gồm tất cả những điều phức tạp.
static_cast <Loại *> (ptr)
Cái này đưa con trỏ vào ptr
và cố gắng đưa nó vào một con trỏ kiểu một cách an toàn Type*
. Diễn viên này được thực hiện tại thời gian biên dịch. Nó sẽ chỉ thực hiện các diễn viên nếu các loại loại có liên quan. Nếu các loại không liên quan, bạn sẽ gặp lỗi trình biên dịch. Ví dụ:
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 <Loại *> (ptr)
Điều này một lần nữa cố gắng đưa con trỏ vào ptr
và đưa nó vào một con trỏ kiểu một cách an toàn Type*
. Nhưng dàn diễn viên này được thực thi trong thời gian chạy, không biên dịch thời gian. Bởi vì đây là một diễn viên thời gian chạy, nó rất hữu ích đặc biệt khi kết hợp với các lớp đa hình. Trong thực tế, trong các trường hợp certian, các lớp phải là đa hình để các diễn viên hợp pháp.
Các diễn viên có thể đi theo một trong hai hướng: từ cơ sở đến dẫn xuất (B2D) hoặc từ dẫn xuất đến cơ sở (D2B). Nó đủ đơn giản để xem các phôi D2B sẽ hoạt động như thế nào trong thời gian chạy. Hoặc ptr
là có nguồn gốc từ Type
hoặc nó không. Trong trường hợp của D2B Dynamic_cast <> s, các quy tắc rất đơn giản. Bạn có thể cố gắng truyền bất cứ thứ gì sang bất cứ thứ gì khác, và nếu ptr
trên thực tế có nguồn gốc từ Type
, bạn sẽ nhận được một Type*
con trỏ trở lại từ đó dynamic_cast
. Nếu không, bạn sẽ nhận được một con trỏ NULL.
Nhưng phôi B2D phức tạp hơn một chút. Hãy xem xét các mã sau đây:
#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()
không thể biết loại đối tượng nào CreateRandom()
sẽ quay trở lại, vì vậy dàn diễn viên theo phong cách C Bar* bar = (Bar*)base;
được quyết định là không an toàn. Làm thế nào bạn có thể khắc phục điều này? Một cách sẽ là thêm một hàm như bool AreYouABar() const = 0;
vào lớp cơ sở và trả về true
từ Bar
và false
từ Foo
. Nhưng có một cách khác: sử dụng 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;
}
Các phôi thực thi trong thời gian chạy và hoạt động bằng cách truy vấn đối tượng (không cần phải lo lắng về việc làm thế nào bây giờ), hỏi nó nếu nó là loại chúng ta đang tìm kiếm. Nếu có, dynamic_cast<Type*>
trả về một con trỏ; nếu không, nó trả về NULL.
Để việc truyền từ cơ sở đến nguồn gốc này hoạt động bằng cách sử dụng dynamic_cast<>
, Base, Foo và Bar phải là thứ mà Standard gọi là các kiểu đa hình . Để trở thành một loại đa hình, lớp của bạn phải có ít nhất một virtual
hàm. Nếu các lớp của bạn không phải là kiểu đa hình, việc sử dụng từ gốc đến gốc dynamic_cast
sẽ không biên dịch. Thí dụ:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
Thêm một chức năng ảo vào cơ sở, chẳng hạn như một dtor ảo, sẽ tạo ra cả hai loại đa hình Base và Der:
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<>
hoạt động của hậu trường (hoặc bao nhiêu C ++ hoạt động), một cuốn sách hay (cũng khá dễ đọc cho một thứ gì đó quá kỹ thuật) là "Mô hình đối tượng C ++" của Lippman. Ngoài ra, các cuốn sách "Thiết kế và tiến hóa của C ++" và "Ngôn ngữ lập trình C ++" của Stroustrup là những tài nguyên tốt, nhưng cuốn sách của Lippman dành riêng cho cách C ++ hoạt động 'đằng sau hậu trường'.