polymorphic base class pointers and template classes

Discussion in 'C++' started by awm129, Jun 7, 2009.

  1. awm129

    awm129 Guest

    I have a need to wrap several different (related) legacy structures in
    thier own classes. This seems to scream template classes with the
    structure type as a template parameter for the creation of a private
    class member of the templated type.

    Now, I would also like to use a polymorphic base class pointer with
    this family of classes (for use with a factory) as well as include
    some common functionallity in a base class. I would also like to
    force the inclusion of this templated private member for each derived
    class. This seems increadibly simple but I can't seem to quite wrap
    my head around how this would work. I want to do something simlar to
    this:

    //
    // base class to implement common functionallity
    //
    template<class T>
    class Base
    {
    virtual T wrappedStruct = 0;
    void foo();
    }

    //
    // derived classes
    //
    template<class T>
    class D1 : Base<T>
    {
    T wrappedStruct;
    }

    int main()
    {
    // assume Bar is a structure type
    Bar s;

    // now I want to use a polymorphic pointer to manage these things
    Base* ptr = DFactory( s );
    }


    I dont think I can create an "untyped" (eg. without the <Type>) Base
    pointer, but then how do I get my polymorphism to work? Does any of
    this make sense? Any ideas? Thanks!
    awm129, Jun 7, 2009
    #1
    1. Advertising

  2. * awm129:
    > I have a need to wrap several different (related) legacy structures in
    > thier own classes. This seems to scream template classes with the
    > structure type as a template parameter for the creation of a private
    > class member of the templated type.
    >
    > Now, I would also like to use a polymorphic base class pointer with
    > this family of classes (for use with a factory) as well as include
    > some common functionallity in a base class. I would also like to
    > force the inclusion of this templated private member for each derived
    > class. This seems increadibly simple but I can't seem to quite wrap
    > my head around how this would work. I want to do something simlar to
    > this:
    >
    > //
    > // base class to implement common functionallity
    > //
    > template<class T>
    > class Base


    This would create a family of distinct base classes.


    > {
    > virtual T wrappedStruct = 0;


    C++ does not support virtual data.


    > void foo();


    What's this for?


    > }


    Missing semicolon.

    Did you intend for Base to have only private (inaccessible) members?



    > //
    > // derived classes
    > //
    > template<class T>
    > class D1 : Base<T>
    > {
    > T wrappedStruct;
    > }



    >
    > int main()
    > {
    > // assume Bar is a structure type
    > Bar s;
    >
    > // now I want to use a polymorphic pointer to manage these things
    > Base* ptr = DFactory( s );


    Why do you want that?

    What is the common functionality for the classes?


    > }
    >
    >
    > I dont think I can create an "untyped" (eg. without the <Type>) Base
    > pointer, but then how do I get my polymorphism to work? Does any of
    > this make sense? Any ideas? Thanks!


    You could always use multiple inheritance, like

    struct Base
    {
    virtual ~Base() {}
    // whatever
    };

    struct MyLegacyClass: Base, LegacyClass
    {
    // Whatever
    };

    However, it may be a disservice to you to suggest anything at all, because while
    you've described roughly a kind of technical solution, you haven't really
    described the problem that this solution was meant to solve, in particular what
    the object factory is meant to solve (and the object factory seems to the reason
    for the wrapping, so if there's a better solution than the factory, which there
    might well be, depending on what the problem is, then ignore the above).


    Cheers & hth.,

    - Alf


    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Jun 7, 2009
    #2
    1. Advertising

  3. awm129

    Guest

    On Jun 7, 2:16 am, "Alf P. Steinbach" <> wrote:
    > * awm129:
    >
    >
    >
    >
    >
    > > I have a need to wrap several different (related) legacy structures in
    > > thier own classes.  This seems to scream template classes with the
    > > structure type as a template parameter for the creation of a private
    > > class member of the templated type.

    >
    > > Now, I would also like to use a polymorphic base class pointer with
    > > this family of classes (for use with a factory) as well as include
    > > some common functionallity in a base class.  I would also like to
    > > force the inclusion of this templated private member for each derived
    > > class.  This seems increadibly simple but  I can't seem to quite wrap
    > > my head around how this would work.  I want to do something simlar to
    > > this:

    >
    > > //
    > > // base class to implement common functionallity
    > > //
    > > template<class T>
    > > class Base

    >
    > This would create a family of distinct base classes.
    >
    > > {
    > >   virtual T wrappedStruct = 0;

    >
    > C++ does not support virtual data.


    Yep, this was more to emphasize my desire to force derived classes to
    have a member of the template type, I realize its not legal C++

    >
    > >   void foo();

    >
    > What's this for?


    so, rename foo() (and taht should be public: void foo();) to public:
    void writeMessageToDatabase()

    >
    > > }

    >
    > Missing semicolon.
    >
    > Did you intend for Base to have only private (inaccessible) members?
    >


    no they will be at least protected, I seem to have omitted all
    accessibility modifiers

    >
    >
    >
    >
    > > //
    > > // derived classes
    > > //
    > > template<class T>
    > > class D1 : Base<T>
    > > {
    > >   T wrappedStruct;
    > > }

    >
    > > int main()
    > > {
    > >   // assume Bar is a structure type
    > >   Bar s;

    >
    > >   // now I want to use a polymorphic pointer to manage these things
    > >   Base* ptr = DFactory( s );

    >
    > Why do you want that?


    See below

    >
    > What is the common functionality for the classes?


    The common functionality would be logging, printing, writting to a
    database, etc

    >
    > > }

    >
    > > I dont think I can create an "untyped" (eg. without the <Type>) Base
    > > pointer, but then  how do I get my polymorphism to work?  Does any of
    > > this make sense?  Any ideas?  Thanks!

    >
    > You could always use multiple inheritance, like
    >
    >     struct Base
    >     {
    >         virtual ~Base() {}
    >         // whatever
    >     };
    >
    >     struct MyLegacyClass: Base, LegacyClass
    >     {
    >         // Whatever
    >     };


    Multiple inheritence might be what I need

    >
    > However, it may be a disservice to you to suggest anything at all, because while
    > you've described roughly a kind of technical solution, you haven't really
    > described the problem that this solution was meant to solve, in particular what
    > the object factory is meant to solve (and the object factory seems to the reason
    > for the wrapping, so if there's a better solution than the factory, which there
    > might well be, depending on what the problem is, then ignore the above).
    >
    > Cheers & hth.,
    >
    > - Alf
    >
    > --
    > Due to hosting requirements I need visits to <url:http://alfps.izfree.com/>.
    > No ads, and there is some C++ stuff! :) Just going there is good. Linking
    > to it is even better! Thanks in advance!- Hide quoted text -
    >
    > - Show quoted text -- Hide quoted text -
    >
    > - Show quoted text -



    Thanks for the response! Here is a bit more background on what I'm
    trying to do:

    These legacy structures are a bunch of different messages. I'm
    reading these off a pipe and they come in randomly. I want to pass
    these to a factory to create the correct type of object and then I
    want to pass these messages to several different handlers. These
    handlers should only process the messages for which they are
    interested in and just ignore the others. I had planned to have each
    handler inherit from a base handler that knows how to process the
    generic message type (type Base in my example above). Each derived
    handler would have overloaded processing methods for the message types
    that they are interested in. That way I can call Process( Base* s )
    on a derived handler and all generic messages are passed through while
    certain message types are caught and processed by an overloaded form
    of Process() in the derived handler. The only place the messages need
    to be handled differently based on type is inside the handlers, I want
    to treat them gernerically outside the handlers; thus my desire for a
    base class pointer. This may be easier to see with more psudo code,
    but I can't post any at the moment. Does this clarify my intents at
    all? Thanks again.
    , Jun 7, 2009
    #3
  4. wrote:

    > Thanks for the response! Here is a bit more background on what I'm
    > trying to do:
    >
    > These legacy structures are a bunch of different messages. I'm
    > reading these off a pipe and they come in randomly. I want to pass
    > these to a factory to create the correct type of object and then I
    > want to pass these messages to several different handlers. These
    > handlers should only process the messages for which they are
    > interested in and just ignore the others. I had planned to have each
    > handler inherit from a base handler that knows how to process the
    > generic message type (type Base in my example above). Each derived
    > handler would have overloaded processing methods for the message types
    > that they are interested in. That way I can call Process( Base* s )
    > on a derived handler and all generic messages are passed through while
    > certain message types are caught and processed by an overloaded form
    > of Process() in the derived handler. The only place the messages need
    > to be handled differently based on type is inside the handlers, I want
    > to treat them gernerically outside the handlers; thus my desire for a
    > base class pointer. This may be easier to see with more psudo code,
    > but I can't post any at the moment. Does this clarify my intents at
    > all? Thanks again.


    Yes, it does clarify. And it also gives an opportunity to point out that
    your design has a few pitfalls you need to look out for.
    The first one is that overload resolution is done on the *static* (or
    declared) type. In order to be able to call the correct overload of the
    processing functions, if you only have a pointer to the base class
    available, you need a double-dispatch mechanism.

    See the output from this program for what I mean:

    #include <iostream>
    using namespace std;

    struct MessageA {};
    struct MessageB {};

    class MessageBase;
    template <class T> class Message;

    void Process(const MessageBase*);
    void Process(const Message<MessageA>*);

    class MessageBase
    {
    public:
    virtual ~MessageBase() {}
    virtual void call_Process() = 0;
    };

    template <class T>
    class Message : public MessageBase, public T
    {
    Message() : MessageBase(), T() {}

    public:
    virtual void call_Process()
    {
    Process(this);
    }
    static Message<T>* create() { return new Message<T>(); }
    };

    void Process(const MessageBase*)
    {
    cout << " Process(const MessageBase*)" << endl;
    }

    void Process(const Message<MessageA>*)
    {
    cout << " Process(const Message<MessageA>*)" << endl;
    }

    int main()
    {
    MessageBase* message1 = Message<MessageA>::create();
    MessageBase* message2 = Message<MessageB>::create();

    cout << "Calling \"Process\" directly" << endl;
    Process(message1);
    Process(message2);

    cout << "Calling \"Process\" indirectly" << endl;
    message1->call_Process();
    message2->call_Process();
    }

    Bart v Ingen Schenau
    --
    a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
    c.l.c FAQ: http://c-faq.com/
    c.l.c++ FAQ: http://www.parashift.com/c -faq-lite/
    Bart van Ingen Schenau, Jun 8, 2009
    #4
  5. awm129

    Guest

    On Jun 8, 2:35 pm, Bart van Ingen Schenau <>
    wrote:
    > wrote:
    > > Thanks for the response!  Here is a bit more background on what I'm
    > > trying to do:

    >
    > > These legacy structures are a bunch of different messages.  I'm
    > > reading these off a pipe and they come in randomly.  I want to pass
    > > these to a factory to create the correct type of object and then I
    > > want to pass these messages to several different handlers.  These
    > > handlers should only process the messages for which they are
    > > interested in and just ignore the others.  I had planned to have each
    > > handler inherit from a base handler that knows how to process the
    > > generic message type (type Base in my example above).  Each derived
    > > handler would have overloaded processing methods for the message types
    > > that they are interested in.  That way I can call Process( Base* s )
    > > on a derived handler and all generic messages are passed through while
    > > certain message types are caught and processed by an overloaded form
    > > of Process() in the derived handler.  The only place the messages need
    > > to be handled differently based on type is inside the handlers, I want
    > > to treat them gernerically outside the handlers; thus my desire for a
    > > base class pointer.  This may be easier to see with more psudo code,
    > > but I can't post any at the moment.  Does this clarify my intents at
    > > all?  Thanks again.

    >
    > Yes, it does clarify. And it also gives an opportunity to point out that
    > your design has a few pitfalls you need to look out for.
    > The first one is that overload resolution is done on the *static* (or
    > declared) type. In order to be able to call the correct overload of the
    > processing functions, if you only have a pointer to the base class
    > available, you need a double-dispatch mechanism.
    >
    > See the output from this program for what I mean:
    >
    > #include <iostream>
    > using namespace std;
    >
    > struct MessageA {};
    > struct MessageB {};
    >
    > class MessageBase;
    > template <class T> class Message;
    >
    > void Process(const MessageBase*);
    > void Process(const Message<MessageA>*);
    >
    > class MessageBase
    > {
    > public:
    >   virtual ~MessageBase() {}
    >   virtual void call_Process() = 0;
    >
    > };
    >
    > template <class T>
    > class Message : public MessageBase, public T
    > {
    >   Message() : MessageBase(), T() {}
    >
    > public:
    >   virtual void call_Process()
    >   {
    >     Process(this);
    >   }
    >   static Message<T>* create() { return new Message<T>(); }
    >
    > };
    >
    > void Process(const MessageBase*)
    > {
    >   cout << "  Process(const MessageBase*)" << endl;
    >
    > }
    >
    > void Process(const Message<MessageA>*)
    > {
    >   cout << "  Process(const Message<MessageA>*)" << endl;
    >
    > }
    >
    > int main()
    > {
    >   MessageBase* message1 = Message<MessageA>::create();
    >   MessageBase* message2 = Message<MessageB>::create();
    >
    >   cout << "Calling \"Process\" directly" << endl;
    >   Process(message1);
    >   Process(message2);
    >
    >   cout << "Calling \"Process\" indirectly" << endl;
    >   message1->call_Process();
    >   message2->call_Process();
    >
    > }
    >
    > Bart v Ingen Schenau
    > --
    > a.c.l.l.c-c++ FAQ:http://www.comeaucomputing.com/learn/faq
    > c.l.c FAQ:http://c-faq.com/
    > c.l.c++ FAQ:http://www.parashift.com/c -faq-lite/


    On Jun 8, 2:35 pm, Bart van Ingen Schenau <>
    wrote:
    > wrote:
    > > Thanks for the response! Here is a bit more background on what I'm
    > > trying to do:

    >
    > > These legacy structures are a bunch of different messages. I'm
    > > reading these off a pipe and they come in randomly. I want to pass
    > > these to a factory to create the correct type of object and then I
    > > want to pass these messages to several different handlers. These
    > > handlers should only process the messages for which they are
    > > interested in and just ignore the others. I had planned to have each
    > > handler inherit from a base handler that knows how to process the
    > > generic message type (type Base in my example above). Each derived
    > > handler would have overloaded processing methods for the message types
    > > that they are interested in. That way I can call Process( Base* s )
    > > on a derived handler and all generic messages are passed through while
    > > certain message types are caught and processed by an overloaded form
    > > of Process() in the derived handler. The only place the messages need
    > > to be handled differently based on type is inside the handlers, I want
    > > to treat them gernerically outside the handlers; thus my desire for a
    > > base class pointer. This may be easier to see with more psudo code,
    > > but I can't post any at the moment. Does this clarify my intents at
    > > all? Thanks again.

    >
    > Yes, it does clarify. And it also gives an opportunity to point out that
    > your design has a few pitfalls you need to look out for.
    > The first one is that overload resolution is done on the *static* (or
    > declared) type. In order to be able to call the correct overload of the
    > processing functions, if you only have a pointer to the base class
    > available, you need a double-dispatch mechanism.
    >
    > See the output from this program for what I mean:
    >
    > #include <iostream>
    > using namespace std;
    >
    > struct MessageA {};
    > struct MessageB {};
    >
    > class MessageBase;
    > template <class T> class Message;
    >
    > void Process(const MessageBase*);
    > void Process(const Message<MessageA>*);
    >
    > class MessageBase
    > {
    > public:
    > virtual ~MessageBase() {}
    > virtual void call_Process() = 0;
    >
    > };
    >
    > template <class T>
    > class Message : public MessageBase, public T
    > {
    > Message() : MessageBase(), T() {}
    >
    > public:
    > virtual void call_Process()
    > {
    > Process(this);
    > }
    > static Message<T>* create() { return new Message<T>(); }
    >
    > };
    >
    > void Process(const MessageBase*)
    > {
    > cout << " Process(const MessageBase*)" << endl;
    >
    > }
    >
    > void Process(const Message<MessageA>*)
    > {
    > cout << " Process(const Message<MessageA>*)" << endl;
    >
    > }
    >
    > int main()
    > {
    > MessageBase* message1 = Message<MessageA>::create();
    > MessageBase* message2 = Message<MessageB>::create();
    >
    > cout << "Calling \"Process\" directly" << endl;
    > Process(message1);
    > Process(message2);
    >
    > cout << "Calling \"Process\" indirectly" << endl;
    > message1->call_Process();
    > message2->call_Process();
    >
    > }
    >
    > Bart v Ingen Schenau
    > --
    > a.c.l.l.c-c++ FAQ:http://www.comeaucomputing.com/learn/faq
    > c.l.c FAQ:http://c-faq.com/
    > c.l.c++ FAQ:http://www.parashift.com/c -faq-lite/


    Excellent point! I had assumed some sort of special processing would
    be needed in the handlers to get to the correct overload, but this
    illustrates the point quite clearly. I didn't think about overload
    resolution being based on the static type... This may throw my design
    out the window altogether.

    As a side note, I ended up abandoning templates for the derived
    classes. It turns out each and every message type would need its own
    specialization anyway which kinda defeats the point of the templates.
    So now I have 20 some odd similar yet different message classes.

    I want this, but I don't think it can work (forgive any typos as I
    don't have a compiler on this machine):


    struct LegacyMessageA {};

    class MessageBase
    {
    public:
    virtual ~MessageBase() {}
    };

    class MessageA : public MessageBase
    {
    public:
    MessageA(const MessageA msg) : MessageBase() //assume msg is copied
    to m_msg
    // assume accessors into m_msg
    // assume common functionality for all messages
    private:
    LegacyMessageA m_msg
    };

    class HandlerBase
    {
    public:
    HandlerBase(){}
    virtual ~HandlerBase(){}
    void process( MessageBase* msg );
    protected:
    void _doProcess( MessageBase* msg );
    };

    HandlerBase::process( MessageBase* msg )
    {
    // this is only ever going to call _doProcess( MessageBase* msg )
    // as opposed to the proper overload for the actual type of msg.
    // I want it to call the proper overload in the derived handler!

    this->_doProcess( msg )
    }

    HandlerBase::_doProcess( MessageBase* msg )
    {
    //do nothing
    }

    class MessageAHandler : HandlerBase
    {
    public:
    DerivedHandler() : HandlerBase() {}
    private:
    _doProcess( MessageA* msg );
    };

    MessageAHandler::_doProcess( MessageA* msg )
    {
    // special handling for type MessageA.
    // I don't think this ever gets called as all messages go
    // to MessageBase::_doProcess( MessageBase* msg )
    }

    int main()
    {
    LegacyMessageA msg;
    MessageBase* message1 = new MessageA( msg );
    HandlerBase* handler = new MessageAHandler();

    handler->process( message1 );

    delete message1;
    delete handler;

    return 0;
    }


    Can this scheme work at all? It all seemed so elegant yesterday!
    , Jun 9, 2009
    #5
  6. wrote:

    > Excellent point! I had assumed some sort of special processing would
    > be needed in the handlers to get to the correct overload, but this
    > illustrates the point quite clearly. I didn't think about overload
    > resolution being based on the static type... This may throw my design
    > out the window altogether.
    >
    > As a side note, I ended up abandoning templates for the derived
    > classes. It turns out each and every message type would need its own
    > specialization anyway which kinda defeats the point of the templates.
    > So now I have 20 some odd similar yet different message classes.
    >
    > I want this, but I don't think it can work (forgive any typos as I
    > don't have a compiler on this machine):


    It can work. Look up the Visitor design pattern, which is basically what
    you need to implement.
    It helps if you have an unchanging set of Message classes, which you
    seem to have.

    >
    >
    > struct LegacyMessageA {};
    >

    You need a forward declaration of HandlerBase:
    class HandlerBase;

    > class MessageBase
    > {
    > public:
    > virtual ~MessageBase() {}

    Here you need a pure-virtual function to make a 'call back' to the
    handler:
    virtual void call_doProcess(HandlerBase*) = 0;
    > };
    >
    > class MessageA : public MessageBase
    > {
    > public:
    > MessageA(const MessageA msg) : MessageBase() //assume msg is copied
    > to m_msg
    > // assume accessors into m_msg
    > // assume common functionality for all messages

    Each concrete Message class must implement the call_doProcess to call
    that function in the handler:
    virtual void call_doProcess(HandlerBase* handler);

    > private:
    > LegacyMessageA m_msg
    > };
    >
    > class HandlerBase
    > {
    > public:
    > HandlerBase(){}
    > virtual ~HandlerBase(){}
    > void process( MessageBase* msg );
    > protected:

    HandlerBase must have the _doProcess functions public (unless you want
    to juggle with friend declarations) and provide a default implementation
    for each concrete Message class:
    public:
    virtual void _doProcess( MessageBase* msg );
    virtual void _doProcess( MessageA* msg)
    { _doProcess(static_cast<MessageBase*>(msg)); }
    > };
    >
    > HandlerBase::process( MessageBase* msg )
    > {
    > // this is only ever going to call _doProcess( MessageBase* msg )
    > // as opposed to the proper overload for the actual type of msg.
    > // I want it to call the proper overload in the derived handler!
    >

    Here you must ask the message to call _doProcess for you:
    msg->call_doProcess(this);

    > this->_doProcess( msg )
    > }
    >
    > HandlerBase::_doProcess( MessageBase* msg )
    > {
    > //do nothing
    > }


    Implementation for the call_doProcess function can come here:
    void MessageA::call_doProcess(HandlerBase* handler)
    {
    handler->_doProcess(this);
    }

    >
    > class MessageAHandler : HandlerBase
    > {
    > public:
    > DerivedHandler() : HandlerBase() {}
    > private:
    > _doProcess( MessageA* msg );
    > };
    >
    > MessageAHandler::_doProcess( MessageA* msg )
    > {
    > // special handling for type MessageA.
    > // I don't think this ever gets called as all messages go
    > // to MessageBase::_doProcess( MessageBase* msg )


    As this now overrides a function of the base class, it can get called by
    MessageA::call_doProcess.

    > }
    >
    > int main()
    > {
    > LegacyMessageA msg;
    > MessageBase* message1 = new MessageA( msg );
    > HandlerBase* handler = new MessageAHandler();
    >
    > handler->process( message1 );
    >
    > delete message1;
    > delete handler;
    >
    > return 0;
    > }
    >
    >
    > Can this scheme work at all? It all seemed so elegant yesterday!


    Yes. With the changes I indicated it becomes a bit less elegant (the
    HandlerBase must know about all the specific messages), but it will
    work.

    Bart v Ingen Schenau
    --
    a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
    c.l.c FAQ: http://c-faq.com/
    c.l.c++ FAQ: http://www.parashift.com/c -faq-lite/
    Bart van Ingen Schenau, Jun 10, 2009
    #6
  7. awm129

    Guest

    On Jun 10, 4:23 am, Bart van Ingen Schenau <>
    wrote:
    > wrote:
    > > Excellent point!  I had assumed some sort of special processing would
    > > be needed in the handlers to get to the correct overload, but this
    > > illustrates the point quite clearly.  I didn't think about overload
    > > resolution being based on the static type... This may throw my design
    > > out the window altogether.

    >
    > > As a side note, I ended up abandoning templates for the derived
    > > classes.  It turns out each and every message type would need its own
    > > specialization anyway which kinda defeats the point of the templates.
    > > So now I have 20 some odd similar yet different message classes.

    >
    > > I want this, but I don't think it can work (forgive any typos as I
    > > don't have a compiler on this machine):

    >
    > It can work. Look up the Visitor design pattern, which is basically what
    > you need to implement.
    > It helps if you have an unchanging set of Message classes, which you
    > seem to have.
    >
    >
    >
    > > struct LegacyMessageA {};

    >
    > You need a forward declaration of HandlerBase:
    >  class HandlerBase;
    >
    > > class MessageBase
    > > {
    > > public:
    > >   virtual ~MessageBase() {}

    >
    > Here you need a pure-virtual function to make a 'call back' to the
    > handler:
    >     virtual void call_doProcess(HandlerBase*) = 0;> };
    >
    > > class MessageA : public MessageBase
    > > {
    > > public:
    > >   MessageA(const MessageA msg) : MessageBase()  //assume msg is copied
    > > to m_msg
    > >   // assume accessors into m_msg
    > >   // assume common functionality for all messages

    >
    > Each concrete Message class must implement the call_doProcess to call
    > that function in the handler:
    >     virtual void call_doProcess(HandlerBase* handler);
    >
    > > private:
    > >   LegacyMessageA m_msg
    > > };

    >
    > > class HandlerBase
    > > {
    > > public:
    > >   HandlerBase(){}
    > >   virtual ~HandlerBase(){}
    > >   void process( MessageBase* msg );
    > > protected:

    >
    > HandlerBase must have the _doProcess functions public (unless you want
    > to juggle with friend declarations) and provide a default implementation
    > for each concrete Message class:
    >   public:
    >     virtual void _doProcess( MessageBase* msg );
    >     virtual void _doProcess( MessageA* msg)
    >     { _doProcess(static_cast<MessageBase*>(msg)); }> };
    >
    > > HandlerBase::process( MessageBase* msg )
    > > {
    > >   // this is only ever going to call _doProcess( MessageBase* msg )
    > >   // as opposed to the proper overload for the actual type of msg.
    > >   // I want it to call the proper overload in the derived handler!

    >
    > Here you must ask the message to call _doProcess for you:
    >     msg->call_doProcess(this);
    >
    > >   this->_doProcess( msg )
    > > }

    >
    > > HandlerBase::_doProcess( MessageBase* msg )
    > > {
    > >   //do nothing
    > > }

    >
    > Implementation for the call_doProcess function can come here:
    > void MessageA::call_doProcess(HandlerBase* handler)
    > {
    >   handler->_doProcess(this);
    >
    > }
    >
    > > class MessageAHandler : HandlerBase
    > > {
    > >   public:
    > >     DerivedHandler() : HandlerBase() {}
    > >   private:
    > >     _doProcess( MessageA* msg );
    > > };

    >
    > > MessageAHandler::_doProcess( MessageA* msg )
    > > {
    > >   // special handling for type MessageA.
    > >   // I don't think this ever gets called as all messages go
    > >   // to MessageBase::_doProcess( MessageBase* msg )

    >
    > As this now overrides a function of the base class, it can get called by
    > MessageA::call_doProcess.
    >
    >
    >
    > > }

    >
    > > int main()
    > > {
    > >   LegacyMessageA msg;
    > >   MessageBase* message1 = new MessageA( msg );
    > >   HandlerBase* handler = new MessageAHandler();

    >
    > >   handler->process( message1 );

    >
    > >   delete message1;
    > >   delete handler;

    >
    > >   return 0;
    > > }

    >
    > > Can this scheme work at all?  It all seemed so elegant yesterday!

    >
    > Yes. With the changes I indicated it becomes a bit less elegant (the
    > HandlerBase must know about all the specific messages), but it will
    > work.
    >
    > Bart v Ingen Schenau
    > --
    > a.c.l.l.c-c++ FAQ:http://www.comeaucomputing.com/learn/faq
    > c.l.c FAQ:http://c-faq.com/
    > c.l.c++ FAQ:http://www.parashift.com/c -faq-lite/



    I had never heard of the visitor design pattern and it seems to very
    much fit what I want to do. I had resigned myself to using RTTI and a
    giant switch in HandlerBase but I like the double dispatch through the
    Message much much better. Thank you very much for the help and
    suggestions, I'm looking forward to getting this thing implemented!
    , Jun 10, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matt Graham
    Replies:
    0
    Views:
    562
    Matt Graham
    Jul 21, 2003
  2. Tim Clacy
    Replies:
    12
    Views:
    613
    Dan W.
    Dec 3, 2003
  3. nguillot
    Replies:
    5
    Views:
    527
  4. Hicham Mouline
    Replies:
    1
    Views:
    590
    Victor Bazarov
    Apr 20, 2009
  5. andy_P
    Replies:
    4
    Views:
    593
    Juha Nieminen
    Nov 15, 2010
Loading...

Share This Page