2011-01-10 31 views
10

Giả sử tôi được cấp một thư viện C++ đầy thừa kế. Tôi được đưa ra một hàm Base* trong một hàm khi tôi biết rằng nó thực sự trỏ đến một đối tượng DerivedDerived kế thừa Base. Nhưng tôi không biết loại thừa kế là gì (công cộng/được bảo vệ/riêng tư). Tôi cũng không biết nếu có bất kỳ chức năng ảo trong hệ thống phân cấp.static_cast vs dynamic_cast

Với tình hình này, mà không nhìn vào mã nguồn/tài liệu của BaseDerived, mà cast tôi nên sử dụng? Hay tôi nên tham khảo mã/tài liệu trước để đảm bảo tính đa hình?

nền

Tôi viết thư này changeEvent chức năng của QMainWindow trong Qt 4.7. Chức năng changeEvent mất QEvent* mà tôi có thể truyền sang loại khác bằng cách biết QEvent::type(). Tôi đã tự hỏi nếu tôi nên sử dụng static_cast hoặc dynamic_cast.

Cảm ơn.

+3

Nếu bất kỳ thư viện nào bạn sử dụng đều sử dụng thừa kế 'được bảo vệ', đã đến lúc tìm thư viện viết tốt hơn. –

+0

Câu hỏi này có thể giúp: http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast –

+2

@Zac: Ước gì tôi có thể bình luận. Làm thế nào bạn có thể đánh giá liệu được thừa kế có bảo vệ hay không là công cụ thích hợp cho công việc nếu bạn không biết thư viện đó làm gì? – Puppy

Trả lời

17

Sử dụng static_cast. Nếu bạn biết rằng Base* điểm của mình là Derived, thì hãy sử dụng static_cast. dynamic_cast hữu ích khi thời điểm có thể trỏ đến nguồn gốc.

+1

Bạn có thể biết bây giờ. Nhưng anh ấy đang sử dụng thư viện và tôi chắc chắn không có thư viện nào được cung cấp bởi thư viện rằng họ sẽ không thay đổi chi tiết triển khai. Giao diện là Base * do đó ** ALL ** bạn có thể giả định. Vì vậy, bạn ** PHẢI ** sử dụng dynamic_cast <> để bạn có thể kiểm tra các giả định của bạn giữ các từ sau. –

+0

@Martin: Đó là vấn đề của anh ấy, không phải của tôi. Nếu anh ta biết * rằng nó thực sự trỏ đến nguồn gốc, thì gốc rễ của kiến ​​thức đó nằm ngoài giới hạn của những gì tôi có thể trả lời. – Puppy

+2

Các probelm là ông không thể biết. Kiến thức của ông được giới hạn trong không gian thời gian được xác định trong trường hợp cụ thể này. Vì vậy chúng ta cần nhấn mạnh rằng OP là sai trong giả định của mình rằng anh ta biết. Bây giờ anh ấy biết nhưng tri thức không thể chuyển nhượng được trong tương lai. Vì vậy, bởi vì anh ta là sai static_cast là câu trả lời sai (đó là câu trả lời đúng nếu OP là chính xác (nhưng ông không phải là)). Thời gian duy nhất bạn có thể giả định giao diện là Derived là khi nó trả về một Derived * nếu không nó có thể trả về bất cứ thứ gì có nguồn gốc từ Base * (đó là lý do tại sao chúng ta có các giao diện trong mã). –

3

Từ MSDN -

Nói chung bạn sử dụng static_cast khi bạn muốn chuyển đổi kiểu dữ liệu số như enums để ints hoặc ints để nổi, và bạn chắc chắn của các kiểu dữ liệu liên quan đến việc chuyển đổi. chuyển đổi static_cast không an toàn như chuyển đổi dynamic_cast, vì static_cast không kiểm tra loại thời gian chạy, trong khi dynamic_cast thực hiện. Một dynamic_cast tới một con trỏ mơ hồ sẽ thất bại, trong khi một static_cast trả về như thể không có gì sai; điều này có thể nguy hiểm. Mặc dù chuyển đổi dynamic_cast an toàn hơn nhưng dynamic_cast chỉ hoạt động trên con trỏ hoặc tham chiếu và kiểm tra loại thời gian chạy là phí trên đầu.

Mọi chi tiết, kiểm tra này link

8

Khi nghi ngờ, bạn nên thích dynamic_cast. Nó có thể chậm hơn, nhưng có thể bạn sẽ không nhận thấy sự khác biệt.

Nếu bạn cần tốc độ, sử dụng đoạn mã sau:

template <typename Derived, typename Base> 
Derived safe_static_cast(Base b) 
{ 
    assert((void*)dynamic_cast<Derived>(b) && "safe_static_cast failed!"); 
    return static_cast<Derived>(b); 
} 

Hoặc một cái gì đó tương đương.

Ý tưởng là trong bản dựng gỡ lỗi, nó kiểm tra xem đó thực sự là những gì bạn nghĩ, và nó phát hành bản dựng ... mọi thứ đã được thử nghiệm chưa?

+1

bạn không cần '(void *)' cast –

+0

@Gene: nó được thừa nhận là xấu xí :) Tôi đã cố gắng tránh quá tải cho trường hợp tham chiếu. –

Các vấn đề liên quan