Wednesday, 4 July 2012

Multiple Inheritance

Found what is probably a 'classic' C++ error today.

We have

Class Message;

Class LogonMessage : public Message

Then we have the processor that is invoked to handle this message which for whatever reason is defined like this:

class ProcessRequest

class ProcessLogonRequest 
    :    public ProcessRequest, 
         public LogonMessage

Now in an exception handler somewhere the code processing a ProcessLogonRequest catches an exception and dies:

void Service::process( ProcessRequest *processRequest )
{
    try
    {
...
    }
    catch( const SomeError& e )
    {
         Message *asMessage = (Message *)processRequest;

         //
         // This crashes
         //
         generateErrorResponse( asMessage->getSomeField() );
    }
}

I amazed this hasn't occurred earlier. I think that because the processor mostly handles all the exceptions (it is only a system error that gets up this far like a DB going away) that it didn't crash earlier.

The problem is of course that Message and ProcessRequest are siblings in the class hierarchy and you can't cast from one to the other. You could first down-cast to a ProcessLogonRequest and then cast to a Message but this isn't possible as the code doesn't know what its got.

Thankfully RTTI is enabled so we just changed this to:

Message *asMessage = dynamic_cast<Message *>(processRequest);

But then there is also a risk that processRequest is an instance of a class NOT derived from a Message so we also needed to handle the case where dynamic_cast returns NULL.

The other way to solve it would be for ProcessRequest to define a virtual method that returns a pointer to itself cast as a Message but then I would have to change every sub-class of ProcessRequest (and these are numerous).

Tom

No comments:

Post a Comment