2010-08-22 28 views
5

Đưa ra một giao diện trừu tượng và triển khai thực hiện từ giao diện đó, nơi các nhà xây dựng được bảo vệ (tạo các đối tượng này chỉ có sẵn từ một nhà máy lớp học - để triển khai mẫu DI). Tôi sử dụng make_shared trong chức năng của nhà máy?Sử dụng make_shared với một constructor được bảo vệ + giao diện trừu tượng

Ví dụ:

class IInterface 
{  
public:  
    virtual void Method() = 0; 
}; 

class InterfaceImpl : public IInterface 
{ 
public: 
    virtual void Method() {} 

protected:  
    InterfaceImpl() {}  
}; 

std::shared_ptr<IInterface> Create() 
{ 
    std::shared_ptr<IInterface> object = std:: make_shared<InterfaceImpl>();  
    return object; 
} 

make_shared rõ ràng là không thể truy cập các nhà xây dựng được bảo hộ tại InterfaceImpl, hoặc thực sự trong IInterface, đem lại cho tôi những lỗi sau


error C2248: 'InterfaceImpl::InterfaceImpl' : cannot access protected member declared in class 'InterfaceImpl' 

Vì vậy, đọc ở đây (câu hỏi: How to make boost::make_shared a friend of my class), Tôi đã thử đưa những điều sau đây vào lớp triển khai:


friend std::shared_ptr<InterfaceImpl> std::make_shared<InterfaceImpl>(); 

Nó vẫn không biên dịch. Vì vậy, sau đó tôi đặt một số khác vào lớp IInterface. Vẫn không có niềm vui. Tôi đã làm gì sai ở đây?

EDIT: nguồn tập tin đầy đủ sử dụng để biên dịch, với "người bạn" ...

#include <memory> 

class IInterface 
{  
public:  
    friend std::shared_ptr&lt;IInterface> Create();  
    virtual void Method() = 0; 
}; 

class InterfaceImpl : public IInterface 
{  
public:  
    virtual void Method() {} 

protected:  
    friend std::shared_ptr&lt;IInterface> Create();  
    InterfaceImpl() {}  
}; 

std::shared_ptr<IInterface> Create() 
{ 
    std::shared_ptr<IInterface> object = std::make_shared<InterfaceImpl>();  
    return object; 
} 

void main() 
{ 
    std::shared_ptr<IInterface> i = Create(); 
} 
+0

Tôi đoán đó là VC10? GCC btw không có vấn đề miễn là bạn làm bạn 'make_shared()'. –

+0

Đó là VS2010, mà thực sự đưa ra một cảnh báo (sai - chi tiết ở đây: http://connect.microsoft.com/VisualStudio/feedback/details/321690/c-vc9-bogus-cảnh báo-c4396-cho-hợp lệ-mã). – Robinson

Trả lời

4

Với VC10 giải pháp bạn có liên quan đến không hoạt động - việc xây dựng các thể hiện của InterfaceImpl không xảy ra trong make_shared, nhưng ở loại nội bộ trong std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void).

Tôi chỉ muốn làm cho Create() chức năng một friend trong trường hợp của bạn và không sử dụng make_shared():

class InterfaceImpl : public IInterface { 
// ...  
protected: 
    friend std::shared_ptr<IInterface> Create(); 
    InterfaceImpl() {} 
}; 

std::shared_ptr<IInterface> Create() { 
    return std::shared_ptr<IInterface>(new InterfaceImpl()); 
} 

... hoặc sử dụng một tùy chỉnh make_shared() thực hiện mà bạn thực sự có thể làm bạn với mà không dựa vào thực xấu xí chi tiết.

Một thay thế sẽ được sử dụng một cái gì đó giống như pass-key-idiom này:

class InterfaceImpl : public IInterface { 
public: 
    class Key { 
     friend std::shared_ptr<IInterface> Create(); 
     Key() {} 
    }; 
    InterfaceImpl(const Key&) {} 
}; 

std::shared_ptr<IInterface> Create() { 
    std::shared_ptr<IInterface> object = 
     std::make_shared<InterfaceImpl>(InterfaceImpl::Key()); 
    return object; 
} 
+0

Điều đó không biên dịch hoặc là tôi sợ! – Robinson

+0

@rob: Huh, tôi đã thử nghiệm nó trong VC10 trước khi đăng bài. Bạn đang thử nghiệm với mã khác nhau? –

+0

Có lẽ tôi đã bỏ lỡ điều gì đó. Đây là mã tôi biên dịch (theo dõi "câu trả lời" vì nhận xét không cho phép mã có vẻ như ...!) ... – Robinson

4

Đối với câu hỏi ban đầu, std :: make_shared < ...>() không trực tiếp khởi tạo lớp học của bạn, vì vậy cung cấp truy cập người bạn để nó không mang lại lợi ích, như bạn tìm thấy. Bạn chỉ có thể cung cấp quyền truy cập người bạn để mã mà không trực tiếp sử dụng constructor bảo vệ bạn như sau:

friend class std::tr1::_Ref_count_obj<TheClassManagedByTheShared_Ptr>; 

hoặc trong trường hợp của bạn:

friend class std::tr1::_Ref_count_obj<InterfaceImpl>; 

này làm việc với các trình biên dịch Microsoft trong VS2010, nhưng có vẻ giống như nó có thể là môi trường cụ thể vì nó không hoạt động với gcc trên Linux. Với gcc std :: tr1 không gian tên không tồn tại, do đó, nó phải được cụ thể cho việc thực hiện Microsoft của thư viện std.

Môi trường làm việc bình thường của tôi là trình biên dịch Intel 12.1, có vẻ như có lỗi không kiểm tra quyền truy cập và vui vẻ xây dựng mã mà không có bất kỳ tuyên bố kết bạn nào.

+0

Đã làm việc với VC2013. Ngay cả khi lớp học của tôi được tô điểm. – fmuecke

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