Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclasses and get_shared_from_this()

I need to find a solution to allow a subclass to get its proper smart pointer.

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.

  ...
}

How do I get the right smart pointer using shared_from_this()?

CONTEXT:

I'm writing a bit of notifier/listener stuff, and some classes will naturally need to register and unregister themselves from the notifier. For example,

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){ ... }

  ...
}

Normally I would just use the this pointer, and all would be well. I've gotten the Notifier to use templates, so I can pass messages only to the ones that want to hear them.

However, I want to use smart pointers. If the notifier looks like this:

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

  ...
}

then I cannot use the this pointer any more. Naturally, I made Body extend enable_shared_from_this:

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

And that seems to works for Bodies. It doesn't work, however, for subclasses of bodies (or, at least, it doesn't seem to):

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

likely because I can't cast a shared_pointer. SO, can I make a solution that

  • lets me use shared pointers for the listeners (since these listeners are also used in other smart pointer contexts),
  • lets me template the Notifier and the listeners, using the message type itself for the template, so it's super easy to listen for the specific messages and so I don't have to decode a message, and
  • is simple?

I'm open to other ideas, but if I can get this to work, I'll be thrilled.

like image 594
whiterook6 Avatar asked Mar 19 '12 19:03

whiterook6


1 Answers

You can cast smart pointers, and Boost provides you with a few templates to ease this. You have eg. static_pointer_cast and dynamic_pointer_cast which allow you to cast "through" the pointer.

Since this is of the right dynamic type, you can invoke boost::static_pointer_cast on the return value of shared_from_this():

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

(no need to qualify static_pointer_cast thanks to Koenig lookup)

like image 181
Alexandre C. Avatar answered Nov 04 '22 17:11

Alexandre C.