2010-08-22 99 views
5

給定一個抽象的接口,並從該接口,在構造函數是保護衍生的實現(這些對象的創建僅是從一個類工廠 - 實現DI模式),如何能我在工廠函數中使用make_shared?使用make_shared與受保護的構造函數+抽象接口

例如:

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顯然無法訪問受保護的構造函數InterfaceImpl,或實際上,IInterface,給我下面的錯誤


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

所以在這裏讀(問題:How to make boost::make_shared a friend of my class)我試圖把下面進入實施類:


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

它仍然不會編譯。於是我又把另一個放到了IInterface類中。仍然沒有快樂。我在這裏做錯了什麼?

編輯:用來編譯完整的源文件,與「朋友」 ......

#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

我想這就是VC10?只要你和'make_shared()'交朋友,GCC btw就沒有問題。 – 2010-08-22 13:48:40

+0

它是VS2010,它實際上給出了一個警告(錯誤 - 詳細在這裏:http://connect.microsoft。COM/VisualStudio中/反饋/信息/ 321690/C-VC9-虛假警告-c4396換有效的代碼)。 – Robinson 2010-08-22 13:49:13

回答

4

隨着VC10您鏈接到該解決方案不起作用 - 的InterfaceImpl實例的建設不會發生在make_shared,但在內部類型std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)

我只是讓Create()功能在你的情況下,friend不使用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()); 
} 

...或使用自定義make_shared()實現,實際上,你可以不依靠醜陋的實施交好細節。

另一種方法是使用這樣的pass-key-idiom

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

這不會編譯我害怕! – Robinson 2010-08-22 14:05:35

+0

@rob:嗯,我在發佈前在VC10中測試過它。你使用不同的代碼進行測試嗎? – 2010-08-22 14:08:52

+0

也許我錯過了一些東西。這裏是我正在編譯的代碼(跟進「答案」,因爲評論不允許代碼,它似乎...!)... – Robinson 2010-08-22 14:11:36

4

原來的問題,的std :: make_shared < ...>()不直接實例化你的類,所以提供給朋友訪問正如你發現的那樣,它沒有任何好處。你可以簡單地提供到不直接使用您的受保護的構造如下代碼朋友訪問:

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

或在您的情況:

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

這適用於VS2010微軟編譯器,但它看起來像它可能是特定於環境的,因爲它在Linux上不適用於gcc。使用gcc std :: tr1命名空間不存在,所以它必須特定於std庫的Microsoft實現。

我正常的工作環境是英特爾編譯器12.1,這似乎有不訪問檢查所有的錯誤,並愉快地構建代碼,而無需任何朋友的聲明。

+0

使用VC2013。即使我的課程是模板化的。 – fmuecke 2015-10-01 19:48:31

相關問題