2012-11-11 37 views
10

Tôi đã đi qua một số mã trong CodeProject và đi qua mã sau đây cho đúc C++.Thực hiện C++ Cast

template <class OutputClass, class InputClass> 
union horrible_union{ 
    OutputClass out; 
    InputClass in; 
}; 
template <class OutputClass, class InputClass> 
inline OutputClass horrible_cast(const InputClass input){ 
    horrible_union<OutputClass, InputClass> u; 
    u.in = input; 
    return u.out; 
} 

Tại sao dàn diễn viên được triển khai ở trên. Tại sao chúng ta không thể làm một dàn diễn viên thủ công. Ai đó có thể đưa ra một ví dụ về khi một diễn viên bình thường sẽ không hoạt động?

+4

Truy cập một thành viên của liên minh sau khi đặt thành viên khác là hành vi không xác định, vì vậy mọi thứ tốt hơn phương pháp 'horrible_union' này. –

+0

Có lẽ đó là lý do tại sao nó được đặt tên là diễn viên khủng khiếp. Đây là cơ bản để thực hiện một số hành vi cụ thể trình biên dịch. – KodeWarrior

Trả lời

9

Phương pháp này về cơ bản cho phép bạn thoát khỏi bất kỳ diễn viên nào, mặc dù nó dựa trên hành vi không xác định.

Một diễn viên bình thường sẽ phàn nàn khi truyền giữa các loại không liên quan, trong khi điều này thì không.

struct A{}; 
struct B{}; 

template <class OutputClass, class InputClass> 
union horrible_union{ 
    OutputClass out; 
    InputClass in; 
}; 
template <class OutputClass, class InputClass> 
inline OutputClass horrible_cast(const InputClass input){ 
    horrible_union<OutputClass, InputClass> u; 
    u.in = input; 
    return u.out; 
} 

int main() 
{ 
    A a; 
    B b; 
    a = horrible_cast<A,B>(b); //this compiles 
    a = reinterpret_cast<A>(b); //this doesn't 
} 

Tóm lại: thật kinh khủng, đừng làm điều đó.

+1

Nếu bạn đang làm việc trên một kiến ​​trúc cụ thể và sử dụng một trình biên dịch cụ thể (đối với một số hệ thống nhúng), nó có thể là một cách tiếp cận hợp lệ để thực hiện chuyển đổi kiểu chỉ có ý nghĩa trên kiến ​​trúc đó. Nhưng nó vẫn nguy hiểm, tôi đồng ý. – bitmask

2

Sử dụng công đoàn theo cách này nói chung tương đương với một số cứng reinterpret_cast của con trỏ. Tuy nhiên, điều đó không sao chép các đối tượng, ví dụ của bạn làm (hai lần ngay cả với RVO, trên thực tế, nó sẽ là khá hiệu quả hơn để có const InputClass& input làm đối số). Vì vậy, bạn có thể trực tiếp hoạt động trên kết quả của nó mà không có khả năng đột biến đối tượng gốc.

Chính xác điều này hữu ích cho ... hm. Tôi không nghĩ rằng có bất kỳ trường hợp sử dụng thực sự tốt, không nên kiểm tra phôi, và như David Hammen nhận xét điều này là thực sự hoàn toàn không xác định (mặc dù nó thường sẽ làm việc, nếu sử dụng "chính xác").

+0

Có lẽ cửa hàng của họ có chính sách chống lại 'reinterpret_cast', nhưng không phải là lỗ hổng này. – Barmar

+0

Trong trường hợp đó sẽ thậm chí còn kinh khủng hơn khi sử dụng nó: 'reinterpret_cast' là nguy hiểm, nhưng điều này là tồi tệ hơn. – leftaroundabout

+0

Cá nhân, tôi muốn thấy rằng 'reinterpret_cast' (và có lẽ phải đi sau khi từ bỏ nếu có một quy tắc chống lại nó) hơn là ẩn các diễn viên như thế này. –