2010-10-13 22 views
5

Tôi đang sử dụng C++. C++ 0x sử dụng Visual Studio 2010 là chính xác.Làm thế nào để con trỏ thông minh không xâm phạm hành xử đối với thừa kế và thừa kế nhiều?

Giả sử tôi có một lớp Z. Để làm cho nó an toàn hơn trong ứng dụng của tôi để làm việc với con trỏ đến lớp này, tôi có thể sử dụng con trỏ thông minh (con trỏ chia sẻ, con trỏ yếu).

Bây giờ lớp này Z kế thừa từ một lớp X. Một số phần của ứng dụng của tôi sẽ làm việc với các con trỏ tới lớp X, những người khác sẽ làm việc với các con trỏ tới lớp Z.

  • Tôi vẫn có thể sử dụng con trỏ thông minh?
  • Các con trỏ được chia sẻ vẫn hoạt động nếu tôi có một số tham chiếu đến X và những người khác tham chiếu đến Z? Nó có đảm bảo rằng sự hủy diệt của con trỏ được chia sẻ cuối cùng cho cá thể (bất kể nó là std::shared_ptr<X> hoặc std::shared_ptr<Z>) xóa cá thể không? Tôi có chắc chắn rằng nếu tôi xóa std::shared_ptr<X>, thì phiên bản đó được giữ miễn là có std::shared_ptr<Y> khác không?

Bây giờ giả sử rằng tôi sử dụng đa kế thừa, nơi Z kế thừa từ các lớp X và Y. Một số phần của ứng dụng của tôi sẽ làm việc với std::shared_ptr<X>, những người khác với std::shared_ptr<Y> và những người khác với std::shared_ptr<Z>.

  • Tôi vẫn có thể sử dụng con trỏ được chia sẻ theo cách này không?
  • Nó vẫn được đảm bảo rằng chỉ có con trỏ thông minh cuối cùng (bất kể nó trỏ đến X, Y hoặc Z) có xóa được cá thể không?

Nhân tiện, làm cách nào tôi có thể truyền một con trỏ thông minh một cách an toàn cho một con trỏ khác, ví dụ: đúc std::shared_ptr<Z> đến std::shared_ptr<X>? Điều này có hiệu quả không? Điều này có được phép không?

Lưu ý rằng tôi đề cập rõ ràng đến các con trỏ không xâm nhập (như mới std::shared_ptrstd::weak_ptr trong C++ 0x). Khi sử dụng con trỏ xâm nhập (như trong Boost), nó có thể hoạt động vì bản thân cá thể có trách nhiệm giữ bộ đếm.

Trả lời

6

Có điều này được hỗ trợ bởi tiêu chuẩn, §20.9.11.2.10 [util.smartptr.shared.cast].

Các utils bạn cần là:

  • std::static_pointer_cast<>()
  • std::dynamic_pointer_cast<>()

Họ có ngữ nghĩa tương tự như C++ 03 phần truy cập của họ static_cast<>()dynamic_cast<>(). Sự khác biệt duy nhất là chúng chỉ hoạt động trên std::shared_ptr s. Và chỉ để tiết lộ, họ làm những gì bạn mong đợi và chia sẻ chính xác số lượng tham chiếu giữa bản gốc và mới được đúc shared_ptr s.

struct X { virtual ~X(){} }; 
struct Y : public X {}; 
struct Z : public X {}; 

int main() 
{ 
    { 
     //C++03 
     X* x = new Z; 
     Z* z = dynamic_cast<Z*>(x); 
     assert(z); 
     x = new Y; 
     z = dynamic_cast<Z*>(x); 
     assert(!z); 
     z = static_cast<Z*>(x); 
     assert(z); //EVIL!!! 
    } 

    { 
     //C++0x 
     std::shared_ptr<X> x{new Z}; 
     std::shared_ptr<Z> z{std::dynamic_pointer_cast<Z>(x)}; 
     assert(z); 
     x = std::make_shared<Y>(); 
     z = std::dynamic_pointer_cast<Z>(x); 
     assert(!z); 
     z = std::static_pointer_cast<Z>(x); 
     assert(z); //EVIL!!! 

     // reference counts work as expected. 
     std::shared_ptr<Y> y{std::static_pointer_cast<Y>(x)}; 
     assert(y); 

     std::weak_ptr<Y> w{y}; 
     assert(w.expired()); 

     y.reset(); 
     assert(w.expired()); 

     x.reset(); 
     assert(!w.expired());  
    } 
    { 
     //s'more nice shared_ptr features 
     auto z = std::make_shared<X>(); 
     std::shared_ptr<X> x{z}; 
     assert(z == x); 
     x = z; //assignment also works. 
    } 
} 
+0

Wow chưa bao giờ nghe về điều này ... O__o Không có tham chiếu đến điều này trong bất kỳ tài nguyên nào tôi có thể tìm thấy trên C++ 0x khác với bản nháp (không rõ ràng) ... – Klaim

+0

Tôi không biết chắc chắn các phôi nơi đó cho đến khi tôi nhìn nó lên. Tôi đã làm tuy nhiên mạnh mẽ nghi ngờ họ đã có như họ là một phần của thư viện Boost.Smartptr ban đầu. –

+0

Hãy loại bỏ "std ::" trước các toán tử dàn dựng sẵn.Ngoài ra, một diễn viên năng động của loại này đòi hỏi các lớp đa hình. Các lớp mẫu của bạn không đa hình. – sellibitze