2010-09-07 25 views
7

Tôi đã thấy rằng một cách hữu ích để viết một phương pháp nhân bản mà trả về một tăng :: shared_ptr là để làmLàm thế nào để Thực hiện một phương pháp nhân bản sử dụng shared_ptr và kế thừa từ enable_shared_from_this

class A 
{ 
public: 
    shared_ptr<A> Clone() const 
    { 
    return(shared_ptr<A>(CloneImpl())); 
    } 
protected: 
    virtual A* CloneImpl() const 
    { 
    return(new A(*this)); 
    } 
}; 

class B : public A 
{ 
public: 
    shared_ptr<B> Clone() const 
    { 
    return(shared_ptr<B>(CloneImpl())); 
    } 
protected: 
    virtual B* CloneImpl() const 
    { 
    return(new B(*this)); 
    } 
}; 

Điều này cho phép việc sử dụng các hiệp phương sai với con trỏ thông thường trong khi vẫn gói nó trong sự an toàn của một con trỏ thông minh. Vấn đề của tôi là lớp B của tôi cần phải kế thừa từ boost :: enable_shared_from_this bởi vì ngay sau khi xây dựng nó cần phải đăng ký chính nó với một lớp riêng biệt, đi qua một con trỏ được chia sẻ cho chính nó. Tôi có một phương pháp Tạo kết thúc tốt đẹp việc xây dựng và đăng ký để đảm bảo rằng chúng luôn xảy ra cùng nhau. Việc thực hiện phương pháp sao chép trên không thể xử lý yêu cầu này, tuy nhiên. Việc đăng ký không thể xảy ra trong CloneImpl vì không có shared_ptr nào tồn tại "sở hữu" đối tượng, ngăn chặn cuộc gọi đến shared_from_this() và nếu logic này không có trong hàm ảo thì shared_ptr trỏ đến B, không biết về nhu cầu đăng ký của B khi nhân bản. Cách tốt nhất để xử lý vấn đề này là gì?

+0

Mã này có biên dịch không? Hình như B :: Clone() ẩn A :: Clone(). –

+0

Ví dụ này được biên soạn cho tôi. Tôi tin rằng đó là mục đích mà B :: Clone() ẩn A :: Clone() để bạn có được kiểu trả về đúng. – user334066

Trả lời

7

Kể từ khi bạn đã thực hiện công giao diện hiệp phương sai cho mình qua Clone() chức năng không ảo, bạn có thể xem xét bỏ hiệp phương sai cho CloneImpl() chức năng.

Nếu bạn chỉ cần shared_ptr và không bao giờ con trỏ thô, vì vậy bạn sau đó có thể làm:

class X 
{ 
public: 
    shared_ptr<X> Clone() const 
    { 
    return CloneImpl(); 
    } 
private: 
    virtual shared_ptr<X> CloneImpl() const 
    { 
    return(shared_ptr<X>(new X(*this))); 
    } 
}; 

class Y : public X 
{ 
public: 
    shared_ptr<Y> Clone() const 
    { 
    return(static_pointer_cast<Y, X>(CloneImpl())); // no need for dynamic_pointer_cast 
    } 
private: 
    virtual shared_ptr<X> CloneImpl() const 
    { 
    return shared_ptr<Y>(new Y(*this)); 
    } 
}; 

CloneImpl() sẽ luôn luôn trả về một shared_ptr<Base> và bây giờ bạn có thể đăng ký đối tượng của bạn bên trong B::CloneImpl() chức năng và trả lại shared_ptr registerd .

+0

Cảm ơn bạn Tôi tin rằng điều này giải quyết vấn đề rất tốt. Trong thực tế, thậm chí bỏ qua các yêu cầu đăng ký, không phương pháp sao chép này có vẻ tốt hơn so với một trong những tôi liệt kê, đó là ví dụ tôi luôn luôn nhìn thấy khi nhân bản với con trỏ thông minh? Phiên bản này dường như cung cấp cho các chức năng tương tự trong khi loại bỏ bất kỳ lạm dụng có thể có của con trỏ thường xuyên được tạo ra trong CloneImpl tôi liệt kê. – user334066

+0

@ user334066 - Tôi đoán nó phụ thuộc. Ví dụ tôi đăng có thể được tìm thấy trên danh sách lưu trữ danh sách gửi thư nâng cao. Chức năng Clone của bạn cho phép sử dụng nội bộ lớp của con trỏ thô có thể có ý nghĩa theo thời gian. –

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