5

抽象インターフェイスとそのインターフェイスから派生した実装があり、コンストラクターが保護されている場合 (これらのオブジェクトの作成はクラス ファクトリからのみ利用可能 - DI パターンを実装するため)、ファクトリ関数で 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'

ここを読んで(質問:boost::make_sharedを私のクラスの友達にする方法)、実装クラスに次のものを入れてみました:


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

それでもコンパイルされません。そこで、もう 1 つ 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();   
}
4

2 に答える 2

4

元の質問に対して、 std::make_shared<...>() はクラスを直接インスタンス化しないため、友人へのアクセスを提供してもメリットはありません。次のように、保護されたコンストラクターを直接使用するコードへのフレンド アクセスを提供するだけです。

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

またはあなたの場合:

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

これは VS2010 の Microsoft コンパイラで動作しますが、Linux の gcc では動作しないため、環境固有のようです。gcc では std::tr1 名前空間は存在しないため、Microsoft の std ライブラリの実装に固有のものでなければなりません。

私の通常の作業環境は Intel 12.1 コンパイラです。これには、アクセスをまったくチェックしないバグがあるようで、フレンド宣言なしで喜んでコードをビルドします。

于 2012-12-11T20:38:17.083 に答える
4

VC10 では、リンク先のソリューションが機能しません。 のインスタンスの構築はInterfaceImplではなくmake_shared、 の内部型で行われstd::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)ます。

あなたのケースでは関数を a にし、使用Create()ませんfriendmake_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;
}
于 2010-08-22T13:59:21.403 に答える