我怎样才能简化这个程序?

时间:2021-04-29 16:54:19

标签: c++ exception

我正在编写一个程序,该程序使用异常处理找到二次方程的根,我想知道是否有一种方法可以简化程序,我有一堆用于捕获案例的空类

// Program to solve quadratic equation
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;


class all_zero{
};

class negative{
};

class zero_division{
};

void roots(double a, double b, double c) throw (all_zero,negative,zero_division);

int main(){
    double a, b, c; // coefficient of ax“2 + bx + c= 0
    cout << "Enter the three coefficients \n";
    cin >> a >> b >> c;

    try
    {
        roots(a, b, c);
    }
    catch(all_zero) {cout << "All values are zero \n";}
    catch(negative) {cout << "Square root of negative values is not defined \n";}
    catch(zero_division) {cout << "Division by zero, not defined \n";}
    return 0;
}

void roots(double a, double b, double c) throw (all_zero,negative,zero_division){
    double x1, x2; // The two roots
    double temp;
    if(!(a== 0 && b== 0 && c==0)){
        if(a != 0){
            temp = b*b - 4*a*c;
            if(temp >= 0){
                x1 =(-b + sqrt(temp))/2*a;
                x2 = (-b - sqrt(temp))/2*a;
                cout << "The two roots are: "<< x1 <<" and " << x2 << endl;
            }else{throw negative();}
        }else{throw zero_division();}
    }else{throw all_zero();}
}

有什么方法可以让我没有空类或将它们放入结构体的方法吗?

2 个答案:

答案 0 :(得分:2)

请注意,您使用的 dynamic excpetion specification 在 C++11 中已弃用,并在 C++17 中删除:

void roots(double a, double b, double c) throw (all_zero,negative,zero_division)
                                      // ^^ 

你可以删除它。


using namespace std;considered bad practice


不要使用 std::endl 添加换行符。 std::endl 添加一个新行并刷新流。大多数时候这是不必要的。使用 '\n' 添加换行符。


<块引用>

有什么方法可以让我没有空类或将它们放入结构体的方法吗?

实际上,我不认为为不同类型的异常设置单独的类有什么坏处。您的方法的缺点是“什么”在 catch 中,而不是异常的一部分或来自异常发生的地方。我将向您展示第一个(消息是类型的一部分),希望您能看到如何实现后者(消息来自抛出异常的地方)。

您可以从 std::runtime_error 继承,它提供了一个 what() 方法,该方法返回传递给构造函数的字符串。这也使其他人更容易捕获您的异常,因为 std::runtime_error 反过来继承自 std::excpetion,它是所有标准异常的基类:

// Program to solve quadratic equation
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <stdexcept>


struct all_zero : std::runtime_error {
    all_zero() : std::runtime_error("All values are zero") {}
};

struct negative : std::runtime_error {
    negative() : std::runtime_error("Square root of negative values is not defined") {}
};

struct zero_division : std::runtime_error {
    zero_division() : std::runtime_error("Division by zero, not defined") {}
};

void roots(double a, double b, double c);

int main(){
    double a, b, c; // coefficient of ax“2 + bx + c= 0
    std::cout << "Enter the three coefficients \n";
    std::cin >> a >> b >> c;

    try
    {
        roots(a, b, c);
    }
    catch(std::runtime_error& ex) {std::cout << ex.what() << '\n';}
    return 0;
}

void roots(double a, double b, double c) {
    double x1, x2; // The two roots
    double temp;
    if(!(a== 0 && b== 0 && c==0)){
        if(a != 0){
            temp = b*b - 4*a*c;
            if(temp >= 0){
                x1 =(-b + sqrt(temp))/2*a;
                x2 = (-b - sqrt(temp))/2*a;
                std::cout << "The two roots are: "<< x1 <<" and " << x2 << "\n";
            }else{throw negative();}
        }else{throw zero_division();}
    }else{throw all_zero();}
}

Live Demo

注意要捕获异常作为引用,否则派生异常时会出现object slicing。通常,您不知道会捕获什么类型的异常,因此您需要小心避免这种情况发生。

或者,您可以使用更通用的异常类型 (roots_exception?),而不是将“what”硬编码到 throw 时将其传递给构造函数。

您可能还有更多可以改进的地方,我建议您https://codereview.stackexchange.com/


PS:我试图将样式放在一边,尽管您应该更改的另一件事是从函数返回结果,而不仅仅是将其打印到屏幕上。如果您想将结果用于其他计算,目前还不能。也许您对如何返回两个值感到困惑。 std::pair 让一切变得简单:

std::pair<double,double> roots(...) {
      // ...
          return {x1,x2};
}

然后:

try {
   auto result = roots(a,b,c);
   std::cout << "The two roots are: "<< result.first <<" and " << result.second << "\n";
}

答案 1 :(得分:0)

我的输入:

  • 确保公式正确。 /2*a 部分应为 /(2*a)
  • 为求解器的错误定义一个错误类别,并从中继承更具体的错误。
  • 删除不必要的测试 (a== 0 && b== 0 && c==0)。您已经检查是否 a == 0,因此如果 a != 0bc 是,解决方案将是 0,这应该是有效的。
  • 反转测试以不必抛出 else。尽早抛出,以免嵌套较深的 if
  • 返回结果,不要打印。我已经添加了一些调整,以便也可以解决线性和复杂的方程(在评论中),但如果你愿意,你可以跳过它。这显示了如何返回多个值。
  • 除非万不得已,否则不要提前声明。
  • 阅读Why is using namespace std; considered bad practice?
  • 代码注释中的更多详细信息
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <tuple> // std::tuple - used for returning multiple values here

struct solver_error : std::runtime_error { // your solver's error category
    using std::runtime_error::runtime_error;
};

struct unknown_error : solver_error {
    unknown_error() : solver_error("x is unknown") {}
};

struct linear_error : solver_error {
    linear_error() : solver_error("cant solve linear equation") {}
};

struct complex_error : solver_error {
    complex_error() : solver_error("cant solve complex equation") {}
};

// add more exceptions to the solver_error exception category if needed
// now returns two values and a bool to indicate if the solution is complex
std::tuple<double, double, bool> solve_for_x(double a, double b, double c) {
    if(a == 0) throw linear_error();   // throw early

    /* ... or solve it as a linear equation:
    if(a == 0) {
        if(b == 0) throw unknown_error(); // both a and b == 0, x is unknown

        double res = -c / b;
        return {res, res, false}; // only one x and not complex
    }
    */

    double div = 2 * a;
    double temp = b * b - 4 * a * c;

    if(temp < 0) throw complex_error();

    /* ... or solve it as a complex equation
    if(temp < 0) {
        double sqr = sqrt(-temp);           // sqrt of the positive temp instead
        return {-b / div, sqr / div, true}; // real, imaginary and complex==true
    }
    */

    // real quadratic
    double sqr = sqrt(temp);
    double x1 = (-b + sqr) / div; // corrected formula (div = 2*a)
    double x2 = (-b - sqr) / div; // corrected formula

    return {x1, x2, false}; // return the two values and complex==false
}
int main() {
    // make the user aware of what the coefficients are for
    std::cout << "Enter the three coefficients a, b and c in the equation\n"
                 "ax^2 + bx + c = 0\n";

    double a, b, c;

    try {
        // check that extracting the numbers succeeds
        if(not(std::cin >> a >> b >> c)) throw std::runtime_error("input error");

        // get the three return values via structured bindings
        auto [first, second, complex] = solve_for_x(a, b, c);

        std::cout << "x = ";

        if(complex)                                   // complex quadratic
            std::cout << first << " ± " << second << 'i';
        else if(first == second)                      // linear
            std::cout << first;
        else                                          // real quadratic
            std::cout << '{' << first << ',' << second << '}';

        std::cout << '\n';

    } catch(const solver_error& ex) {
        // catching the generic error category by "const&"
        std::cerr << "Solver error: " << ex.what() << '\n';
        return 1;

    } catch(const std::runtime_error& ex) {
        std::cerr << ex.what() << '\n';
        return 1;
    }
}