Поймать производное исключение при возврате ссылки типа базового класса? - PullRequest
3 голосов
/ 20 августа 2010

Я пишу приложение для Windows на C ++ и столкнулся со следующей проблемой при работе с исключениями.

У меня есть базовый класс исключений, из которого происходят все остальные исключения. В базовом классе у меня есть метод для сообщения об ошибке любого исключения. Затем этот метод возвращает исключение (через '* this').

Теперь проблема возникает, когда я хочу расширить производное исключение, а затем использовать его в блоке перехвата. Поскольку метод extends объявлен в базовом классе, блок catch перехватывает базовый класс вместо производного класса. Есть ли способ обойти это так, чтобы вместо этого перехватывался правильный производный класс?

Вот код, иллюстрирующий проблему:


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

На данный момент я «решил» это, не , делающий метод расширения виртуальным, но объявив его в каждом исключении с правильным типом возвращаемого значения. Это работает, но это не красиво.

Ответы [ 4 ]

5 голосов
/ 20 августа 2010

Было бы намного проще отделить вызов extend() и повторный вызов исключения:

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

Таким образом extend() не должно ничего возвращать и всегда правильные исключенияброшены / пойманы.

0 голосов
/ 20 августа 2010

Вы должны сделать функцию расширения виртуальной и возвращать DerivedException & в переопределении DerivedException.Это допустимо только для особых случаев, когда возвращаемое значение может быть неявно приведено - например, когда исходная сигнатура функции возвращает базовый класс возвращаемого значения сигнатуры переопределенной функции, как я покажу ниже.

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

ОтображаетDerivedException!

0 голосов
/ 20 августа 2010

Это можно сделать, используя " Любопытно повторяющийся шаблон "

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

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

        return (TExc) *this; 
    } 
} 

class DerivedException : public BaseException<DerivedException> { 
    DerivedException() : BaseException() { } 
}
0 голосов
/ 20 августа 2010

Проблема заключается в том, что возвращаемый тип расширения - «BaseException &». Следовательно, throw exc.extend () пойман не в том обработчике исключений.

Если вы хотите сгенерировать то же исключение, команда use может использовать пустой бросок; заявление. У кода ОП было много ошибок.

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;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...