+5  A: 

It would be much simpler to separate the extend() call and the re-throwing of the exception:

 catch ( DerivedException& exc ) {
     exc.extend( "message2" );
     throw;
 }

This way extend() doesn't have to return anything and always the right exceptions are thrown/caught.

sth
+1 Even though there are no copies being made, doing it the way the OP tried to do it brings up all the same issues involved with implementing a covariant `clone` method (aka virtual copy constructor), which are many.
Tyler McHenry
Ah yes, this does indeed solve the exception problem. Quite clever, that. I'll start refactoring my code right this minute! ^^
gablin
A: 

The problem is that return type of extend is 'BaseException&'. Therefore 'throw exc.extend()' is caught in the wrong exception handler.

If you want to throw the same exception, use can use the empty throw; statement. The OP code had lots of errors.

class BaseException {
public:
    BaseException() { } 

    BaseException& extend( string message ) { 
        // extend message 

        return *this; 
    } 
}; 

class DerivedException : public BaseException { 
public:
    DerivedException() : BaseException() { } 
}; 



// RUNNING CODE 

int main() { 
   try { 

      try { 
         // Something goes wrong 
         throw DerivedException(); 
      } 
      catch ( DerivedException& exc ) { 
         throw exc.extend("A"); 
      } 
   } 
   catch ( DerivedException& ) { 
      // Here is where I *want* to land 
      int i = 0;
   } 
   catch ( BaseException& ) { 
      // Here is where I *do* land 
      int i = 0;
   }
}
Chubsdad
Well I didn't run the code through a compiler as I thought it would be sufficient enough to carry out my point. But agreed, code should always be compilable; I'll take note till next time. ^^ Indeed, I also suspected that the catch didn't work as expected due to it explicitly returning the base class...
gablin
A: 

This can be done using the "Curiously recurring template pattern"

template <typename TExc>
class BaseException { 
    BaseException() { } 

    TExc& extend( string message ) { 
        // extend message 

        return (TExc) *this; 
    } 
} 

class DerivedException : public BaseException<DerivedException> { 
    DerivedException() : BaseException() { } 
}
James Curran
Except now you can't catch a `BaseException`. And yes, you could make a non-templated `BaseException` and then derive a `TemplatedBaseException` from it and use CRTP below that, but then you run into all sorts of hurt if you want to have an `extend` method in the non-templated `BaseException` class (what should it return?)
Tyler McHenry
Yes, I also considered using a template, but as Tyler McHenry aptly pointed out there would be problems with having a non-templated BaseException; hence I abandoned this approach.
gablin
A: 

You should make the extend function virtual, and return a DerivedException& in the DerivedException's override. This is legal only for special cases where the return value can be implicitly casted - such as where the original function signature returns a base class of the override function signature's return value, as I show below.

class BaseException {
public:
    BaseException() { }

    virtual BaseException& extend( std::string message ) {
        // extend message

        return *this;
    }
};

class DerivedException : public BaseException {
public:
    virtual DerivedException& extend( std::string message ) {
        return *this;
    }
    DerivedException(std::string) : BaseException() { }
};



// RUNNING CODE

int main() {
    try {
         try {
             // Something goes wrong
             throw DerivedException( "message1" );
         }
         catch ( DerivedException& exc ) {
             throw exc.extend( "message2" );
         }
    }
    catch ( DerivedException& ) {
        std::cout << "DerivedException!";
    }
    catch ( BaseException& ) {
        std::cout << "BaseException!";
    }
    std::cin.get();
}

Displays DerivedException!

DeadMG
But how does this approach really differ from what I'm currently using? Yes, the method is declared virtual, meaning that there will always be an extend() method in all exception classes; but I still must declare and implement such a method in every derived method which really does the exact same thing. That's what I wanted to avoid...
gablin
Make it into a static templated function. It's true that you still have to write it - but it can be a one-liner.
DeadMG