2010-04-22 17 views
19
using namespace boost; 

class A {}; 
class B : public A {}; 

class X { 
    virtual shared_ptr<A> foo(); 
}; 

class Y : public X { 
    virtual shared_ptr<B> foo(); 
}; 

Los tipos de devolución no son covariantes (ni son, por lo tanto, legales), pero lo serían si estuviera usando punteros sin procesar. ¿Cuál es el modismo comúnmente aceptado para solucionar este problema, si es que existe?Cómo lograr tipos de retorno covariantes al devolver un shared_ptr?

+1

posible duplicado de http://stackoverflow.com/questions/196733/how-can-i-use-covariant-return-types-with-smart-pointers –

Respuesta

11

Creo que una solución es fundamentalmente imposible porque la covarianza depende de la aritmética del puntero que es incompatible con los punteros inteligentes.

Cuando Y::foo devuelve shared_ptr<B> a una persona que llama dinámica, que se tiene que convertir shared_ptr<A> antes de su uso. En su caso, un B* puede (probablemente) simplemente reinterpretarse como A*, pero para la herencia múltiple, necesitaría algo de magia para decirle a C++ sobre static_cast<A*>(shared_ptr<B>::get()).

+0

Hmm, "fundamentalmente" la covarianza depende de la conversión, y quizás debería funcionar con tipos implícitamente convertibles. Pero eso aún no se aplicaría a 'shared_ptr'. – Potatoswatter

+0

"_Pero eso todavía no se aplica a' shared_ptr'_ "No lo entiendo: ¿' shared_ptr' no es convertible? – curiousguy

+0

@curiousguy Oh, uy lo es. Sin embargo, solo es un hipotético. – Potatoswatter

4

No directamente, pero puede falsificarlo haciendo que las funciones virtuales reales sean inaccesibles desde fuera de la clase y envolviendo la llamada de función virtual en una función no virtual. Lo malo es que tendrá que recordar implementar esta función de contenedor en cada clase derivada. Pero podría evitar esto colocando tanto la declaración de la función virtul como la envoltura en la macro.

using namespace boost; // for shared_ptr, make_shared and static_pointer_cast. 

// "Fake" implementation of the clone() function. 
#define CLONE(MyType) \ 
    shared_ptr<MyType> clone() \ 
    { \ 
     shared_ptr<Base> res = clone_impl(); \ 
     assert(dynamic_cast<MyType*>(res.get()) != 0); \ 
     return static_pointer_cast<MyType>(res); \ 
    } 

class Base 
{ 
protected: 
    // The actual implementation of the clone() function. 
    virtual shared_ptr<Base> clone_impl() { return make_shared<Base>(*this); } 

public: 
    // non-virtual shared_ptr<Base> clone(); 
    CLONE(Base) 
}; 

class Derived : public Base 
{ 
protected: 
    virtual shared_ptr<Base> clone_impl() { return make_shared<Derived>(*this); } 

public: 
    // non-virtual shared_ptr<Derived> clone(); 
    CLONE(Derived) 
}; 


int main() 
{ 
    shared_ptr<Derived> p = make_shared<Derived>(); 
    shared_ptr<Derived> clone = p->clone(); 

    return 0; 
} 
+0

Ha pasado un tiempo desde que esto fue respondido. Ahora que C++ 11 está fuera, ¿hay una mejor manera? –

+0

@CoryBeutler. No, si quieres usar shared_ptr. Si está dispuesto a renunciar a shared_ptr y está dispuesto a utilizar el recuento de referencias intrusivas, entonces sí. En este caso, las funciones devolverán punteros sin procesar y para obtener recuento automático solo necesita asignar el resultado a un puntero inteligente (por ejemplo, boost :: intrusive_ptr). – lego

-1

Acabo de devolver un puntero desnudo y envolverlo inmediatamente en el puntero compartido.

+0

Casi nunca desea envolver el puntero descubierto de otra persona a shared_ptr. – ShitalShah

Cuestiones relacionadas