2010-09-07 10 views
7

ho visto che un modo utile per scrivere un metodo clone che restituisce un boost :: shared_ptr è quello di fareCome Fare un metodo clone utilizzando shared_ptr e che eredita da enable_shared_from_this

class A 
{ 
public: 
    shared_ptr<A> Clone() const 
    { 
    return(shared_ptr<A>(CloneImpl())); 
    } 
protected: 
    virtual A* CloneImpl() const 
    { 
    return(new A(*this)); 
    } 
}; 

class B : public A 
{ 
public: 
    shared_ptr<B> Clone() const 
    { 
    return(shared_ptr<B>(CloneImpl())); 
    } 
protected: 
    virtual B* CloneImpl() const 
    { 
    return(new B(*this)); 
    } 
}; 

Questo consente l'uso di covarianza con il puntatore regolare mentre lo si avvolge nella sicurezza di un puntatore intelligente. Il mio problema è che la mia classe B ha bisogno di ereditare da boost :: enable_shared_from_this perché subito dopo la costruzione ha bisogno di registrarsi con una classe separata, passando un puntatore condiviso a se stesso. Ho un metodo Create che avvolge la costruzione e la registrazione per assicurarci che si verifichino sempre insieme. L'implementazione del metodo clone di cui sopra non può tuttavia gestire questo requisito. La registrazione non può avvenire in CloneImpl dal momento che nessun shared_ptr esiste ancora "possedere" l'oggetto, impedendo una chiamata a shared_from_this(), e se questa logica non è in funzione virtuale poi uno shared_ptr che punta a B, non conosce le esigenze di registrazione di B quando clonato. Qual è il modo migliore per gestire questo problema?

+0

Compilare questo codice? Sembra che B :: Clone() nasconda A :: Clone(). –

+0

Questo esempio è stato compilato per me. Credo che sia intenzionale che B :: Clone() nasconda A :: Clone() in modo da ottenere il tipo di ritorno corretto. – user334066

risposta

7

Dal momento che si sta già attuando il pubblico interfaccia covarianza te stesso attraverso i non virtuali Clone() funzioni, si può considerare l'abbandono della covarianza per le CloneImpl() funzioni.

Se avete solo bisogno shared_ptr e mai il puntatore cruda, così si potrebbe poi fare:

class X 
{ 
public: 
    shared_ptr<X> Clone() const 
    { 
    return CloneImpl(); 
    } 
private: 
    virtual shared_ptr<X> CloneImpl() const 
    { 
    return(shared_ptr<X>(new X(*this))); 
    } 
}; 

class Y : public X 
{ 
public: 
    shared_ptr<Y> Clone() const 
    { 
    return(static_pointer_cast<Y, X>(CloneImpl())); // no need for dynamic_pointer_cast 
    } 
private: 
    virtual shared_ptr<X> CloneImpl() const 
    { 
    return shared_ptr<Y>(new Y(*this)); 
    } 
}; 

CloneImpl() sarebbe sempre restituire un shared_ptr<Base> e ora è possibile registrare l'oggetto all'interno della funzione B::CloneImpl() e restituire lo shared_ptr registerd .

+0

Grazie, credo che questo risolva il problema molto bene. Infatti, anche ignorando il requisito di registrazione, questo metodo di clonazione non sembra migliore di quello che ho elencato, che è l'esempio che vedo sempre quando clonando con puntatori intelligenti? Questa versione sembra dare la stessa funzionalità rimuovendo qualsiasi possibile uso improprio del puntatore normale che viene creato in CloneImpl I elencato. – user334066

+0

@ user334066 - Credo che dipenda. L'esempio che ho pubblicato può essere trovato negli archivi della mailing list di boost. La tua funzione di clonazione è consentita per l'uso interno alla classe del puntatore raw che può avere senso di volta in volta. –

Problemi correlati