Domanda

Dato un'interfaccia astratta e un'implementazione derivato da tale interfaccia, in cui i costruttori sono protetti (creazione di questi oggetti solo essere disponibili da una fabbrica di classe - per implementare un modello di DI), come posso fare uso di make_shared nella funzione di fabbrica ?

Ad esempio:

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, ovviamente, non può accedere il costruttore protetto in InterfaceImpl, o addirittura in IInterface, dandomi il seguente errore


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

Quindi, leggere qui (domanda: Come fare boost :: make_shared un amico della mia classe ), ho cercato di mettere quanto segue nella classe di implementazione:


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

E 'ancora non sarebbe la compilazione. Allora ho messo un altro nella classe IInterface troppo. Ancora nessuna gioia. Che cosa ho fatto di male qui?

EDIT: il file sorgente completo utilizzato per la compilazione, con "amico" ...

#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();   
}
È stato utile?

Soluzione

Con VC10 la soluzione si è collegato al non funziona -. La costruzione della istanza di InterfaceImpl non avviene in make_shared, ma in un tipo interno std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)

Vorrei solo fare la funzione Create() un friend nel tuo caso e Non utilizzare 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());
}

... o utilizzare un'implementazione make_shared() personalizzata che in realtà si può fare amicizia senza fare affidamento su dettagli di implementazione brutte.

Un'alternativa sarebbe quella di utilizzare qualcosa di simile pass-key-idioma :

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;
}

Altri suggerimenti

Per la domanda iniziale, std :: make_shared <...> () non istanziare direttamente la classe, in modo da fornire l'accesso amico ad esso produce alcun beneficio, come l'avete trovato. Si può semplicemente fornire amico l'accesso al codice che fa uso direttamente il vostro costruttore protetta come segue:

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

o nel tuo caso:

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

Questo funziona con il compilatore Microsoft in VS2010, ma sembra che potrebbe essere specifico ambiente in quanto non funziona con gcc su Linux. Con gcc lo spazio dei nomi std :: tr1 non esiste, quindi deve essere specifico per l'implementazione Microsoft di libreria std.

Il mio ambiente di lavoro normale è il compilatore Intel 12.1, che sembra avere un bug che non controlla per l'accesso a tutti, e felicemente costruisce codice senza alcuna dichiarazione amico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top