2009-08-31 35 views
67

Cập nhật: shared_ptr trong ví dụ này giống như trong Boost, nhưng nó không hỗ trợ shared_polymorphic_downcast (hoặc dynamic_pointer_cast hoặc static_pointer_cast cho vấn đề đó)!Downcasting shared_ptr <Base> to shared_ptr <Derived>?

Tôi đang cố gắng để khởi tạo một con trỏ chia sẻ cho một lớp học có nguồn gốc mà không làm mất tính tham khảo:

struct Base { }; 
struct Derived : public Base { }; 
shared_ptr<Base> base(new Base()); 
shared_ptr<Derived> derived; 

// error: invalid conversion from 'Base* const' to 'Derived*' 
derived = base; 

Cho đến nay, như vậy tốt. Tôi đã không mong đợi C + + để ngầm chuyển đổi Base * thành Derived *. Tuy nhiên, tôi muốn các chức năng thể hiện bằng mã (có nghĩa là, duy trì số lượng tham chiếu trong khi downcasting con trỏ cơ sở). Suy nghĩ đầu tiên của tôi là cung cấp một nhà điều hành dàn diễn viên trong cơ sở để một chuyển đổi ngầm để nguồn gốc có thể xảy ra (ví pedants: Tôi sẽ kiểm tra xem các diễn viên xuống là hợp lệ, đừng lo lắng):

struct Base { 
    operator Derived*(); 
} 
// ... 
Base::operator Derived*() { 
    return down_cast<Derived*>(this); 
} 

Vâng, nó không giúp được gì. Dường như trình biên dịch hoàn toàn bỏ qua toán tử định kiểu của tôi. Bất kỳ ý tưởng làm thế nào tôi có thể làm cho việc phân công shared_ptr làm việc? Đối với các điểm phụ: loại Base* const là gì? const Base* Tôi hiểu, nhưng Base* const? const đề cập đến trong trường hợp này là gì?

+0

Tại sao bạn cần shared_ptr , thay vì shared_ptr ? – Bill

+2

Vì tôi muốn truy cập chức năng trong Nguồn gốc không có trong Cơ sở, mà không nhân bản đối tượng (tôi muốn một đối tượng duy nhất, được tham chiếu bởi hai con trỏ được chia sẻ). Nhân tiện, tại sao các nhà khai thác không hoạt động? –

Trả lời

45

Tôi giả sử bạn đang sử dụng boost::shared_ptr ... Tôi nghĩ bạn muốn dynamic_pointer_cast hoặc shared_polymorphic_downcast. Tuy nhiên,

Các loại này đòi hỏi các loại đa hình.

loại loại Base* const là? const Base* Tôi hiểu, nhưng Base* const? const đề cập đến trong trường hợp này là gì?

  • const Base * là một con trỏ có thể thay đổi để một hằng số Base.
  • Base const * là một con trỏ có thể thay đổi thành hằng số Base.
  • Base * const là một con trỏ không đổi cho một biến thể Base.
  • Base const * const là một con trỏ không đổi thành hằng số Base.

Dưới đây là một ví dụ nhỏ:

struct Base { virtual ~Base() { } }; // dynamic casts require polymorphic types 
struct Derived : public Base { }; 

boost::shared_ptr<Base> base(new Base()); 
boost::shared_ptr<Derived> derived; 
derived = boost::static_pointer_cast<Derived>(base); 
derived = boost::dynamic_pointer_cast<Derived>(base); 
derived = boost::shared_polymorphic_downcast<Derived>(base); 

Tôi không chắc chắn nếu nó là cố ý rằng ví dụ của bạn tạo ra một thể hiện của các loại cơ sở và phôi nó, nhưng nó phục vụ để minh họa sự khác biệt độc đáo.

static_pointer_cast sẽ "chỉ cần thực hiện". Điều này sẽ dẫn đến hành vi không xác định (một Derived* trỏ vào bộ nhớ được phân bổ và khởi tạo bởi Base) và có khả năng sẽ gây ra sự cố hoặc tệ hơn. Số tham chiếu trên base sẽ được tăng lên.

dynamic_pointer_cast sẽ dẫn đến con trỏ rỗng. Số tham chiếu trên base sẽ không thay đổi.

shared_polymorphic_downcast sẽ có kết quả tương tự như một diễn viên tĩnh, nhưng sẽ kích hoạt xác nhận, thay vì dường như thành công và dẫn đến hành vi không xác định. Số tham chiếu trên base sẽ được tăng lên.

Xem (dead link):

Đôi khi nó là một chút khó khăn để quyết định có nên sử dụng static_cast hay dynamic_cast, và bạn muốn bạn có thể có một chút của cả hai thế giới. Nó cũng được biết rằng dynamic_cast có một chi phí thời gian chạy, nhưng nó là an toàn hơn, trong khi static_cast không có chi phí ở tất cả, nhưng nó có thể không âm thầm. Sẽ tốt đến mức nào nếu bạn có thể sử dụng shared_dynamic_cast trong bản dựng gỡ lỗi và shared_static_cast trong bản dựng bản phát hành. Vâng, một điều như vậy đã có sẵn và được gọi là shared_polymorphic_downcast.

+0

Thật không may, giải pháp của bạn phụ thuộc vào chức năng Tăng cường được cố ý loại trừ khỏi việc thực hiện shared_ptr cụ thể mà chúng tôi đang sử dụng (không hỏi tại sao). Đối với giải thích const, bây giờ nó có ý nghĩa hơn nhiều. –

+3

Ngắn của việc triển khai các hàm tạo 'shared_ptr' khác (lấy' static_cast_tag' và 'dynamic_cast_tag'), bạn không thể làm được gì nhiều. Bất kỳ điều gì bạn làm bên ngoài 'shared_ptr' sẽ không thể quản lý số lần truy cập. - Trong một thiết kế OO "hoàn hảo", bạn luôn có thể sử dụng kiểu cơ sở, và không bao giờ cần phải biết và cũng không quan tâm đến kiểu dẫn xuất là gì, bởi vì tất cả các chức năng của nó được hiển thị thông qua các giao diện lớp cơ sở. Có lẽ bạn chỉ cần suy nghĩ lại lý do tại sao bạn cần phải hạ xuống ở vị trí đầu tiên. –

+1

@Tim Sylvester: nhưng, C++ không phải là ngôn ngữ OO "hoàn hảo"! :-) down-phôi có vị trí của họ trong một ngôn ngữ OO không hoàn hảo –

55

Bạn có thể sử dụng dynamic_pointer_cast. Nó được hỗ trợ bởi std::shared_ptr.

std::shared_ptr<Base> base (new Derived()); 
std::shared_ptr<Derived> derived = 
       std::dynamic_pointer_cast<Derived> (base); 

Ngoài ra, tôi không khuyên bạn sử dụng toán tử cast trong lớp cơ sở. Việc truyền ngầm như thế này có thể trở thành nguồn gốc của lỗi và lỗi.

-Cập nhật: Nếu loại không đa hình, std::static_pointer_cast có thể được sử dụng.

+3

Tôi đã không hiểu từ dòng đầu tiên mà anh ta không sử dụng 'std :: shared_ptr'. Nhưng từ các ý kiến ​​của câu trả lời đầu tiên tôi suy ra rằng anh ta không sử dụng boost, vì vậy anh ta có thể đang sử dụng 'std :: shared_ptr'. –

+0

OK. Lấy làm tiếc. Anh ta nên làm rõ hơn là anh ta đang sử dụng một triển khai tùy chỉnh. –

3

Nếu ai đó nhận được ở đây với tăng :: shared_ptr ...

Đây là cách bạn có thể downCast đến shared_ptr Boost có nguồn gốc. Giả sử thừa hưởng Derived từ Base.

boost::shared_ptr<Base> bS; 
bS.reset(new Derived()); 

boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS); 
std::cout << "DerivedSPtr is: " << std::boolalpha << (dS.get() != 0) << std::endl; 

Đảm bảo lớp/cấu trúc 'Cơ sở' có ít nhất một hàm ảo. Một destructor ảo cũng hoạt động.

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