开发者

Catch derived exception when returning reference of base class type?

I'm writing a windows application in C++ and encountered the following problem when working with exceptions.

I have a base exception class from which all other exceptions derive from. In the base class I have a method for the error message of any exception. That method then returns the exception (through '*this').

Now, the problem occurs when I want to extend a derived exception and later user it in a catch block. Since the extend method is declared in the base class, the catch block catches the base class instead of the derived class. Is there any way of working around this so that the correct derived class is caught instead?

Here are some code illustrating the problem:


// DECLARATIONS

class BaseException {
    BaseException() { }

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

        return *this;
    }
}

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



// RUNNING CODE

int main() {
    try {
         ...

         try {
             ...

             // Something goes wrong
             throw DerivedException( "message1" );
         }
         catch ( DerivedException& exc ) {
             throw exc.extend( "message2" );
         }
    }
    catch ( DerivedException& ) {
        // Here is where I *want* to land开发者_运维知识库
    }
    }
    catch ( BaseException& ) {
        // Here is where I *do* land
    }
}

At the moment I have "solved" it by not making the extend method virtual, but declaring it in each exception with correct return type. It works, but it's not pretty.


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.


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


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;
   }
}


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!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜