usuario try tratamiento todas son solo que propias programacion por personalizadas personalizada nuestras mis manejo los lista letras las lanzamiento jerarquia instrucciones identificar hacer excepciones excepcion errores ejemplos ejemplo definidas custom crear con como clases clase catch arbol c++ exception custom-exceptions

c++ - try - ¿Cómo crear excepciones?



try catch solo letras java (4)

Puede crear su propia clase de excepción para error de longitud como este

class MyException : public std::length_error{ public: MyException(const int &n):std::length_error(to_string(n)){} };

Por lo tanto, tengo una próxima tarea que trata sobre las excepciones y las uso en mi programa actual de la libreta de direcciones en la que se centra la mayor parte de la tarea. Decidí jugar con las excepciones y todo el intento de captura y uso de un diseño de clase, que es lo que eventualmente tendré que hacer para mi asignación en un par de semanas. Tengo un código de trabajo que verifica la excepción muy bien, pero lo que quiero saber es si hay una manera de estandarizar mi función de mensaje de error, (es decir, mi llamada what) ().

Aquí está mi código:

#include <iostream> #include <exception> using namespace std; class testException: public exception { public: virtual const char* what() const throw() // my call to the std exception class function (doesn''t nessasarily have to be virtual). { return "You can''t divide by zero! Error code number 0, restarting the calculator..."; // my error message } void noZero(); }myex; //<-this is just a lazy way to create an object int main() { void noZero(); int a, b; cout << endl; cout << "Enter a number to be divided " << endl; cout << endl; cin >> a; cout << endl; cout << "You entered " << a << " , Now give me a number to divide by " << endl; cin >> b; try { myex.noZero(b); // trys my exception from my class to see if there is an issue } catch(testException &te) // if the error is true, then this calls up the eror message and restarts the progrm from the start. { cout << te.what() << endl; return main(); } cout <<endl; cout << "The two numbers divided are " << (a / b) << endl; // if no errors are found, then the calculation is performed and the program exits. return 0; } void testException::noZero(int &b) //my function that tests what I want to check { if(b == 0 ) throw myex; // only need to see if the problem exists, if it does, I throw my exception object, if it doesn''t I just move onto the regular code. }

Lo que me gustaría poder hacer es hacerlo para que mi función what () pueda devolver un valor dependiendo de qué tipo de error se está detectando. Entonces, por ejemplo, si estuviera llamando un error que parecía ser el número superior, (a), para ver si era un cero, y si lo era, entonces se configuraría el mensaje para decir que "no se puede tener un numerador de cero ", pero aún así estar dentro de la función what (). Aquí hay un ejemplo:

virtual const char* what() const throw() if(myex == 1) { return "You can''t have a 0 for the numerator! Error code # 1 " } else return "You can''t divide by zero! Error code number 0, restarting the calculator..."; // my error message }

Esto obviamente no funcionaría, pero ¿hay una manera de hacerlo para que no esté escribiendo una función diferente para cada mensaje de error?


Su código contiene una gran cantidad de conceptos erróneos. La respuesta corta es sí, puedes cambiar what() para devolver lo que quieras. Pero vamos paso a paso.

#include <iostream> #include <exception> #include <stdexcept> #include <sstream> using namespace std; class DivideByZeroException: public runtime_error { public: DivideByZeroException(int x, int y) : runtime_error( "division by zero" ), numerator( x ), denominator( y ) {} virtual const char* what() const throw() { cnvt.str( "" ); cnvt << runtime_error::what() << ": " << getNumerator() << " / " << getDenominator(); return cnvt.str().c_str(); } int getNumerator() const { return numerator; } int getDenominator() const { return denominator; } template<typename T> static T divide(const T& n1, const T& n2) { if ( n2 == T( 0 ) ) { throw DivideByZeroException( n1, n2 ); } return ( n1 / n2 ); } private: int numerator; int denominator; static ostringstream cnvt; }; ostringstream DivideByZeroException::cnvt;

En primer lugar, runtime_error , derivado de la exception , es la clase de excepción recomendada para derivar. Esto se declara en el encabezado stdexcept. Solo tiene que inicializar su constructor con el mensaje que va a devolver en el método what() .

En segundo lugar, debes nombrar apropiadamente tus clases. Entiendo que esto es solo una prueba, pero un nombre descriptivo siempre ayudará a leer y entender su código.

Como puede ver, he cambiado el constructor para aceptar los números para dividir lo que provocó la excepción. Hiciste la prueba en la excepción ... bueno, he respetado esto, pero como una función estática que se puede invocar desde el exterior.

Y finalmente, el método what() . Ya que estamos dividiendo dos números, sería bueno mostrar que dos números provocaron la excepción. La única forma de lograrlo es mediante el uso de ostringstream. Aquí lo hacemos estático, por lo que no hay problema en devolver un puntero a un objeto de pila (es decir, tener cnvt una variable local introduciría un comportamiento indefinido).

El resto del programa es más o menos como lo anotó en su pregunta:

int main() { int a, b, result; cout << endl; cout << "Enter a number to be divided " << endl; cout << endl; cin >> a; cout << endl; cout << "You entered " << a << " , Now give me a number to divide by " << endl; cin >> b; try { result = DivideByZeroException::divide( a, b ); cout << "/nThe two numbers divided are " << result << endl; } catch(const DivideByZeroException &e) { cout << e.what() << endl; } return 0; }

Como puede ver, he eliminado su instrucción return main() . No tiene sentido, ya que no se puede llamar a main() recursivamente. Además, el objetivo de eso es un error: esperaría volver a intentar la operación que provocó la excepción, pero esto no es posible, ya que las excepciones no son reentrantes. Sin embargo, puede cambiar un poco el código fuente para lograr el mismo efecto:

int main() { int a, b, result; bool error; do { error = false; cout << endl; cout << "Enter a number to be divided " << endl; cout << endl; cin >> a; cout << endl; cout << "You entered " << a << " , Now give me a number to divide by " << endl; cin >> b; try { result = DivideByZeroException::divide( a, b ); // trys my exception from my class to see if there is an issue cout << "/nThe two numbers divided are " << result << endl; } catch(const DivideByZeroException &e) // if the error is true, then this calls up the eror message and restarts the progrm from the start. { cout << e.what() << endl; error = true; } } while( error ); return 0; }

Como puede ver, en caso de error, la ejecución sigue hasta que se ingresa una división "adecuada".

Espero que esto ayude.


Debes considerar una jerarquía de clases.

El motivo puede no ser obvio cuando se trata de usar excepciones solo para transferir una cadena, pero la intención real de usar excepciones debería ser un mecanismo para el manejo avanzado de situaciones excepcionales. Se están haciendo muchas cosas bajo el capó del entorno de ejecución de C ++, mientras que la pila de llamadas se desenrolla cuando se pasa de "lanzar" a la "captura" correspondiente.

Un ejemplo de las clases podría ser:

class DivisionError : public std::exception { public: DevisionError(const int numerator, const int divider) :numerator(numerator) , divider(divider) { } virtual const char* what() const noexcept { // ... } int GetNumerator() const { return numerator; } int GetDevider() const { return divider; } private: const int numerator; const int divider; }; class BadNumeratorError : public DivisionError { public: BadNumeratorError(int numerator, int divider) : DivisionError(numerator, divider) { } virtual const char* what() const noexcept { { // ... } }; class ZeroDeviderError : public DivisionError { public: ZeroDeviderError(int numerator, int divider) : DivisionError(numerator, divider) { } virtual const char* what() const noexcept { { // .... } };

  • Al proporcionar diferentes clases para los errores, le da a los desarrolladores la oportunidad de manejar diferentes errores de maneras particulares (no solo mostrar un mensaje de error)
  • Al proporcionar una clase base para los tipos de error, permite a los desarrolladores ser más flexibles, ser tan específicos como lo necesiten.

En algunos casos, tienen que ser específicos.

} catch (const ZeroDividerError & ex) { // ... } catch (const DivisionError & ex) {

en otros, no

} catch (const DivisionError & ex) {

En cuanto a algunos detalles adicionales,

  • No debe crear objetos de sus excepciones antes de lanzar de la manera que lo hizo. Independientemente de su intención, es simplemente inútil; de todos modos, está trabajando con una copia del objeto en la sección de captura (no se confunda con el acceso a través de la referencia)
  • Usar una referencia constante sería una catch (const testException &te) buen estilo catch (const testException &te) menos que realmente necesite un objeto no constante.

class zeroNumerator: public std::exception { const char* what() const throw() { return "Numerator can''t be 0./n"; } }; //... try { myex.noZero(b); // trys my exception from my class to see if there is an issue if(myex==1) { throw zeroNumerator(); // This would be a class that you create saying that you can''t have 0 on the numerator } } catch(testException &te) { cout << te.what() << endl; return main(); }

Siempre debes usar std :: exception & e. así que

catch(std::exception & e) { cout<<e.what(); }