如何创建例外?

Cha*_*e M 20 c++ exception custom-exceptions

所以我有一个即将到来的任务处理异常并在我当前的地址簿程序中使用它们,大多数功课都集中在这里.我决定玩异常和整个尝试捕获的东西,并使用类设计,这是我最终将在几周内完成我的任务.我有工作代码检查异常就好了,但我想知道的是,是否有办法标准化我的错误消息功能,(即我的what()调用):

这是我的代码:

#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.
  }
Run Code Online (Sandbox Code Playgroud)

我希望能够做到的是使我的what()函数可以返回一个值,该值取决于调用的错误类型.因此,举例来说,如果我调用一个看起来是最高号码的错误,(a),看看它是否为零,如果是,那么它会设置消息说"你不能有分子为零",但仍然在what()函数内.这是一个例子:

  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
  }
Run Code Online (Sandbox Code Playgroud)

这显然是行不通的,但有没有办法让它成为我不是为每个错误信息编写不同的函数?

Bal*_*arq 37

您的代码包含许多误解.简短的回答是肯定的,你可以改变what(),以便返回你想要的任何东西.但让我们一步一步走.

#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;
Run Code Online (Sandbox Code Playgroud)

首先runtime_error,派生自exception,是派生的建议异常类.这是在stdexcept头中声明的.您只需使用要在what()方法中返回的消息初始化其构造函数.

其次,你应该适当地命名你的课程.我知道这只是一个测试,但描述性名称总是有助于阅读和理解您的代码.

正如您所看到的,我已经更改了构造函数,以便接受引发异常的数字.你在异常中做过测试......好吧,我尊重这个,但作为一个可以从外部调用的静态函数.

最后,what()方法.由于我们将两个数字分开,因此最好显示两个引发异常的数字.实现这一目标的唯一方法是使用ostringstream.这里我们使它静态,因此没有返回指向堆栈对象的指针的问题(即,有cnvt一个局部变量会引入未定义的行为).

程序的其余部分或多或少都与您在问题中列出的一样:

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;

}
Run Code Online (Sandbox Code Playgroud)

如您所见,我已删除您的return main()指示.它没有意义,因为你不能main()递归调用.此外,这样做的目的是错误:您希望重试引发异常的操作,但这是不可能的,因为异常不是可重入的.但是,您可以稍微更改源代码,以达到相同的效果:

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;

}
Run Code Online (Sandbox Code Playgroud)

如您所见,如果出现错误,则执行后直到输入"正确"除法.

希望这可以帮助.

  • 它确实不是强制性的,但它更容易(runtime_error为字符串提供构造函数以设置主要错误消息)并且可能比直接从异常派生更重要(因为您遵循"建议的"标准异常层次结构).除此之外,是的,如果你喜欢这样做,你甚至可以抛出int. (2认同)
  • 不会``返回cnvt.str().c_str();``what()`导致问题?str()返回一个临时副本,c_str()指向该temp中的内部缓冲区,一旦返回,temp被销毁,返回的指针(由c_str()给出)现在无效..? (2认同)
  • @Baltasarq 遗憾的是,将“cnvt”设为静态既不能解决也不能减轻问题。静态 'cnvt' 仍然通过 'str()' 方法创建了一个本地字符串对象,然后返回一个指向后者内部的指针。此外,&lt;&lt; 运算符可以抛出违反 throw() 规范的异常。 (2认同)