2010-04-22 7 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(); 
}; 

I tipi di ritorno non sono covarianti (e non sono, quindi, legali), ma lo sarebbero se usassi invece dei puntatori grezzi. Qual è l'idioma comunemente accettato per aggirare questo, se ce n'è uno?Come eseguire tipi di ritorno covarianti quando si restituisce un parametro shared_ptr?

+1

possibile duplicato di http://stackoverflow.com/questions/196733/how-can-i-use-covariant-return-types-with-smart-pointers –

risposta

11

Penso che una soluzione sia fondamentalmente impossibile perché la covarianza dipende dall'aritmetica del puntatore che è incompatibile con i puntatori intelligenti.

Quando Y::foo restituisce shared_ptr<B> in un chiamante dinamico, è necessario eseguire il cast su shared_ptr<A> prima dell'utilizzo. Nel tuo caso, un B* può (probabilmente) essere semplicemente reinterpretato come A*, ma per l'ereditarietà multipla, è necessario un po 'di magia per dire a C++ su static_cast<A*>(shared_ptr<B>::get()).

+0

Hmm, la covarianza "fondamentalmente" dipende dalla conversione e forse dovrebbe funzionare con tipi implicitamente convertibili. Ma questo non si applicherebbe a 'shared_ptr'. – Potatoswatter

+0

"_Ma questo non si applicherebbe a' shared_ptr'_ "Non capisco: sono' shared_ptr' non convertibile? – curiousguy

+0

@curiousguy Oh, oops lo è. Ancora solo un ipotetico però. – Potatoswatter

4

Non direttamente, ma è possibile simularlo rendendo le funzioni virtuali effettive inaccessibili dall'esterno della classe e avvolgendo la chiamata di funzione virtuale in una funzione non virtuale. Il rovescio della medaglia è che dovrete ricordare di implementare questa funzione wrapper su ogni classe derivata. Ma potresti aggirare questo mettendo sia la dichiarazione della funzione virtul che il wrapper nella 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

È passato un po 'di tempo da quando è stata data una risposta. Ora che C++ 11 è fuori, c'è un modo migliore? –

+0

@CoryBeutler. No, se vuoi usare shared_ptr. Se sei disposto a rinunciare a shared_ptr e sei disposto a utilizzare il conteggio dei riferimenti intrusivi, allora sì. In questo caso le funzioni restituiscono puntatori grezzi e per ottenere il conteggio automatico automatico è sufficiente assegnare il risultato a un puntatore intelligente (ad esempio boost :: intrusive_ptr). – lego

-1

Ho appena restituito un puntatore nudo e lo avvolgo immediatamente nel puntatore condiviso.

+0

Quasi mai non vuoi racchiudere il puntatore nudo di qualcun altro su shared_ptr. – ShitalShah

Problemi correlati