2012-02-28 15 views
8

Vì vậy, tôi đã được đọc những câu trả lời cho dynamic_cast from "void *" và mặc dù bạn không thể đúc từ một void * đến một T * số các phản ứng chỉ ra rằng nó có thể cast một T * đến một void *, nhưng không đưa ra bất cứ dấu hiệu tại sao bạn muốn làm điều đó.Tại sao tôi nên sử dụng dynamic_cast để truyền tới khoảng trống *?

Đây có phải là một chút thông tin có thể xảy ra hoặc có trường hợp nào hợp lý không? Tôi nghĩ về có thể cho dễ đọc hoặc để làm cho nó rõ ràng rằng chúng tôi đang chuyển đổi sang một void *, nhưng với mục đích của dynamic_cast, nó không phù hợp rất tốt với tôi.

Vì lý do đó, có lý do gì để làm bất cứ điều gì khác ngoài việc để T * trở thành void * hoàn toàn không? Tôi đã nhìn thấy phôi kiểu C đến void * được sử dụng theo thời gian cho mục đích này, tôi giả sử chỉ để được rõ ràng (giả sử chúng tôi không làm một cái gì đó bất thường như đúc int cho một con trỏ hoặc một cái gì đó).

+0

Theo như tôi có thể biết, kết quả của việc sử dụng dynamic_cast () và sử dụng chuyển đổi ẩn để void * luôn trả về cùng một kết quả nếu loại nguồn là đa hình. Tôi cho rằng bạn có thể sử dụng nó như một static_assert (is_polymophic (x)), nhưng tôi thực sự không thể nghĩ ra một lý do chính đáng để làm điều đó. –

Trả lời

7

Trước tiên, khi sử dụng dynamic_cast<void*>(x), bạn sẽ nhận được một con trỏ tới byte đầu tiên của đối tượng được xuất phát nhiều nhất. Miễn là loại tĩnh của x là đa hình.

Điều này có thể hữu ích trong một số ít các kịch bản, nơi địa chỉ đóng vai trò như nhận dạng đối tượng:

  • bây giờ bạn có một cách để phân biệt đầy đủ các con trỏ tới subobjects của cùng một đối tượng từ con trỏ để subobjects không liên quan.
  • bây giờ bạn có thể đi bộ một số biểu đồ xoắn mà không cần truy cập cùng một đối tượng nhiều lần ... có thể được sử dụng cho serialization.

Cấp, điều này chắc chắn không phải là một sử dụng hàng ngày , nhưng trong C++ địa chỉ bộ nhớ là một định danh de-facto cho các đối tượng, do đó, một cơ chế để truy cập nó từ bất cứ phần nào của hệ thống phân cấp thừa kế chắc chắn là hữu ích cho những trường hợp ít cạnh đó.

+1

Vì vậy, nếu tôi sử dụng một con trỏ lớp cơ sở và truyền nó đến lớp dẫn xuất, giá trị địa chỉ thực tế có thể khác nhau? Xin lỗi nếu đó là một câu hỏi ngớ ngẩn, tôi đã chỉ để cho nó được phép thuật với tôi cho hầu hết các phần;). – FatalError

+3

@FatalError: (lưu ý: thảo luận thực dụng) trong trường hợp thừa kế đơn, với lớp cơ sở là đa hình, địa chỉ thực ra phải giống nhau. Tuy nhiên ngay sau khi bạn bắt đầu thừa kế thừa kế thừa hoặc nếu cơ sở không đa hình nhưng lớp dẫn xuất là, thì địa chỉ có thể thay đổi. Bạn có thể nghĩ về một lớp cơ sở là thuộc tính đầu tiên (ẩn) -> sau khi tất cả chúng là lần đầu tiên trong danh sách khởi tạo của một hàm tạo; do đó, khi có nhiều lớp, sự bắt đầu của cơ sở thứ hai và nguồn gốc hiện tại không trùng với bất kỳ trường hợp ngoại lệ nào nữa. –

+1

Tôi đã thử nó và bạn đã chính xác đúng, khi tôi đã thử với nhiều thừa kế tôi thấy địa chỉ thay đổi với dàn diễn viên năng động nhưng không phải với dàn diễn viên tĩnh hoặc dàn diễn viên kiểu C. Cảm ơn! – FatalError

5

Có một mục đích cho điều này, được. Nó được ám chỉ trong một phần của spec cho phép nó. Từ N3337, phần 5.2.7, khoản 7:

If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v.

Vì vậy, một dynamic_cast<void*>(...) thực sự là viết tắt cho static_cast<void*>(dynamic_cast<MostDerivedType*>(...)). Và điều đó sẽ hữu ích ... loại.

Khó khăn trong việc làm cho nó hữu ích là bạn không nhất thiết phải biết những gì MostDerivedType là. Sau khi tất cả, nó có thể khác nhau cho mỗi biểu thức. Vì vậy, một khi bạn có nó như là một void*, bạn không nhất thiết phải có một cách để đúc nó trở lại một cách an toàn. Nếu bạn đoán được khoảng MostDerivedType và chỉ static_cast nó và bạn đang sai, thì bạn đang ở trong vùng hành vi chưa được xác định. Trong khi nếu bạn làm dynamic_cast cho loại đó (sau đó static_cast đến void*), nó sẽ ít nhất trả về NULL nếu nó không thuộc loại đó.

Vì vậy, không, tôi sẽ nói rằng nó không phải là rất hữu ích. Không phải nếu bạn muốn sống trong ranh giới của C++ và không dựa vào hành vi có khả năng không xác định.

+0

Nếu bạn có hai con trỏ đối tượng, bạn không nhất thiết phải biết liệu chúng trỏ đến cùng một đối tượng - với nhiều thừa kế, chúng có thể trỏ đến các đối tượng con khác nhau của cùng một đối tượng. Để xem chúng có cùng một đối tượng hay không, hãy đưa cả hai vào 'void *' và so sánh kết quả. Windows COM có một quy tắc tương tự: 'QueryInterface' cho' IUnknown', và bạn sẽ nhận được kết quả tương tự cho cùng một đối tượng, cho dù bạn bắt đầu với giao diện nào của đối tượng đó. –

+0

Điều đó không giải thích tại sao 'dynamic_cast' cần thực hiện điều đó. 'static_cast' đã được cho là hoạt động theo cùng một cách. –

+0

@NicolBolas: 'static_cast' không hoạt động với thừa kế ảo. –

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