Como blocos catch são avaliados (C++)
O C++ permite lançar exceções de qualquer tipo, embora seja recomendável lançar os tipos derivados de std::exception. Uma exceção de C++ pode ser capturada por um manipulador catch que especifica o mesmo tipo da exceção lançada, ou por um manipulador que pode capturar qualquer tipo de exceção.
Se o tipo de exceção lançada for uma classe, que também tenha uma classe base (ou classes), ela pode ser capturada pelos manipuladores que aceitam classes base do tipo da exceção, bem como por referências às bases do tipo da exceção. Observe que, quando uma exceção é capturada por uma referência, ela é associada ao objeto de exceção lançado real; caso contrário, é uma cópia (bem semelhante a um argumento para uma função).
Quando uma exceção é lançada, ela pode ser capturada pelos seguintes tipos de manipuladores catch:
Um manipulador que pode aceitar qualquer tipo (usando a sintaxe de reticências).
Um manipulador que aceita o mesmo tipo do objeto de exceção; como é uma cópia, os modificadores const e volatile são ignorados.
Um manipulador que aceita uma referência para mesmo tipo do objeto de exceção.
Um manipulador que aceita uma referência para uma forma de const ou volatile do mesmo tipo do objeto de exceção.
Um manipulador que aceita uma classe base do mesmo tipo do objeto de exceção; como é uma cópia, os modificadores const e volatile são ignorados. O manipulador catch para uma classe base não deve preceder o manipulador catch da classe derivada.
Um manipulador que aceita uma referência a uma classe base do mesmo tipo do objeto de exceção.
Um manipulador que aceita uma referência para uma forma de const ou volatile de uma classe base do mesmo tipo do objeto de exceção.
Um manipulador que aceita um ponteiro no qual um objeto de ponteiro gerado pode ser convertido pelas regras padrão de conversão de ponteiro.
A ordem em que os manipuladores catch aparecem é importante, pois os manipuladores para determinado bloco try são verificados pela ordem em que aparecem. Por exemplo, é um erro para colocar o manipulador de uma classe base antes do manipulador de uma classe derivada. Depois que a correspondência para um manipulador catch é encontrada, os manipuladores subsequentes não são verificados. No resultado, um manipulador catch de reticências deve ser o último manipulador do bloco try. Por exemplo:
// ...
try
{
// ...
}
catch( ... )
{
// Handle exception here.
}
// Error: the next two handlers are never examined.
catch( const char * str )
{
cout << "Caught exception: " << str << endl;
}
catch( CExcptClass E )
{
// Handle CExcptClass exception here.
}
Neste exemplo, o manipulador catch de reticências é o único manipulador verificado.