Pregunta

Dada una interfaz abstracta y una implementación derivada de la interfaz, donde los constructores están protegidos (creación de estos objetos sólo está disponible a partir de un generador de clases - para implementar un patrón DI), ¿cómo puedo hacer uso de make_shared en la función de fábrica ?

Por ejemplo:

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 obviamente no puede acceder al constructor protegida en InterfaceImpl, o incluso en IInterface, y me da el siguiente error


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

Así que leer aquí (pregunta: ¿Cómo hacer impulso :: make_shared un amigo de mi clase ), he intentado poner el siguiente en la clase de implementación:


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

Se seguiría sin compilar. Entonces me puse otra en la clase IInterface también. Aún no hay alegría. ¿Qué he hecho mal?

EDIT: archivo de código fuente completo utilizado para compilar, con "amigo" ...

#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();   
}
¿Fue útil?

Solución

Con VC10 la solución se enlazó a no funciona -. La construcción de la instancia de InterfaceImpl no sucede en make_shared, pero en un tipo interno en std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)

Yo sólo haría la función Create() un friend en su caso y No utilice 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 utilizar una aplicación personalizada make_shared() que realmente puede hacerse amigo sin depender de los detalles de implementación feas.

Una alternativa sería utilizar algo como esto pass-clave-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;
}

Otros consejos

A la pregunta original, std :: make_shared <...> () no crea directamente a su clase, por lo que proporciona acceso amigo para que no presenta ningún beneficio, como lo encontró. Simplemente puede proporcionar amigo acceso al código que no utiliza directamente el constructor protegida de la siguiente manera:

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

o en su caso:

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

Esto funciona con el compilador Microsoft en VS2010, pero parece que puede ser entorno específico, ya que no funciona con gcc en Linux. Con gcc no existe el espacio de nombres std :: TR1, por lo que debe ser específico para la implementación de Microsoft de la biblioteca std.

Mi entorno de trabajo normal es el compilador de Intel 12.1, que parece tener un error que no comprueba para el acceso en absoluto, y felizmente se basa código sin ninguna declaración amigo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top