2012-03-19 14 views
7

Devo trovare una soluzione per consentire a una sottoclasse di ottenere il proprio puntatore intelligente.Sottoclassi e get_shared_from_this()

class Parent : public enable_shared_from_this { 
    ... 
} 

class Child : public Parent { 
    public Child(){ 
    boost::shared_ptr<Parent> pointer=shared_from_this(); // should work 
    boost::shared_ptr<Child> pointer=shared_from_this(); // won't work. 

    ... 
} 

Come faccio ad avere il puntatore intelligente destra utilizzando shared_from_this()?

CONTESTO:

sto scrivendo un po 'di roba notificante/ascoltatore, e alcune classi sarà naturalmente necessario registrarsi e si annullare la registrazione al notificatore. Ad esempio,

class Body : extends Listener<BodyMessage>{ // listen for BodyMessage messages 
    public: 
    Body() { 
     Notifier<BodyMessage>::register(this); // register with the appropriate notifier 
    } 

    virtual ~Body { 
     Notifier<BodyMessage>::unregister(this); // unregister 
    } 

    bool notify(BodyMessage m){ ... } 

    ... 
} 

Normalmente mi sarebbe solo utilizzare il puntatore questo, e tutto sarebbe andato bene. Ho ottenuto che Notifier usasse i modelli, così posso passare i messaggi solo a quelli che vogliono ascoltarli.

Tuttavia, voglio utilizzare i puntatori intelligenti. Se il notificante è simile al seguente:

template<typename t> 
class Notifier { 
    public: 
    static void register<boost::shared_ptr<Listener<t>>> boost::shared_ptr<Listener<t>> listener); 

    ... 
} 

quindi non posso utilizzare il puntatore questo più. Naturalmente, ho fatto corpo estendere enable_shared_from_this:

class Body : public boost::enable_shared_from_this, public Listener<BodyMessage> { 
    public: 
    Notifier<BodyMessage>::register(get_shared_ptr()); 
    ... 
} 

E che sembra opere per Enti. Non funziona, tuttavia, per sottoclassi dei corpi (o, almeno, non sembra):

class BodyChild : public Body { 
    public: 
    BodyChild(){ 
     Notifier<BodyMessage>::register(get_shared_ptr()); 
} 

probabilmente perché non riesco a lanciare uno shared_pointer. Allora, posso ottenere una soluzione che

  • mi permette di usare puntatori condivisi per gli ascoltatori (dal momento che questi ascoltatori sono utilizzati anche in altri contesti di puntatore intelligente),
  • mi permette di template Notifier e gli ascoltatori, utilizzando il tipo di messaggio stesso per il modello, quindi è estremamente semplice ascoltare i messaggi specifici e quindi non devo decodificare un messaggio, e
  • è semplice?

Sono aperto ad altre idee, ma se riesco a farlo funzionare, sarò elettrizzato.

+0

divertenti, mi sono imbattuto contro questo molto problema oggi. L'utilizzo di puntatori intelligenti per il pattern Observer si è rivelato un'ottima idea. Puoi anche usare 'boost :: signals' per far eseguire la metà del lavoro automaticamente (specialmente con gli oggetti' scoped_connection'). –

+0

Perché hai bisogno/vuoi 'std :: shared_ptr' per il tuo sistema notificatore/listener?Gli ascoltatori dovrebbero essere effettivamente di proprietà dei notificanti, in modo che vengano distrutti una volta che tutti i notificanti sono spariti? O ci sono in realtà altri oggetti, che possiedono gli oggetti in ascolto e possono occuparsi dell'istanziazione e della costruzione? Quando ho costruito un sistema del genere, ho trovato abbastanza utile mantenere un sacco di controllo e non darlo via. – LiKao

+0

@LiKao: Un modo per scrivere il pattern di osservatore è infatti di far sì che gli ascoltatori mantengano in vita i notificanti e di annullare la distruzione (shared_ptr + boost :: signal è eccellente per scrivere questo in <50 LOC). Al contrario, ho scoperto che attenersi a qualcosa di molto semplice e rigido in questa situazione aiuta a scrivere un codice migliore (leggi: più mantenibile). –

risposta

6

È possibile puntare i puntatori intelligenti e Boost fornisce alcuni modelli per facilitare questo. Hai eg. static_pointer_cast e dynamic_pointer_cast che consentono di eseguire il cast "attraverso" il puntatore.

Dal this è di tipo dinamico a destra, è possibile richiamare boost::static_pointer_cast sul valore di ritorno di shared_from_this():

boost::shared_ptr<Child> p = static_pointer_cast<Child>(shared_from_this()); 

(senza necessità di qualificare static_pointer_cast grazie alla risoluzione di Koenig)

+1

static_pointer_cast (...) è probabilmente il modo migliore per andare in questo caso; Grazie. Naturalmente, mi sto rendendo conto che probabilmente non posso avere entrambi i puntatori intelligenti usati dal notificatore e che gli oggetti si aggiungono alla costruzione, perché il puntatore intelligente di un oggetto non è "disponibile" fino a quando i costruttori non hanno finito. – whiterook6