2017-08-18 132 views
1

我正在学习C++。这里是我的问题:C++简单函数困境

简单的“计算器”程序:读取两个数字和一个符号,将它们传递给函数calculate,返回值或错误,如果禁止输入char。我想出了两个版本的函数,我不知道哪一个是“正确的”。他们是:

第一个直接打印,这不是一个好的做法(是吗?)。

void calculate(int x, int y, char s) { 
    switch (s) { 
    case ('+'): { 
    std::cout << x + y << "\n"; 
    } 
    case ('-'): { 
    std::cout << x - y << "\n"; 
    } 
    case ('*'): { 
    std::cout << x * y << "\n"; 
    } 
    case ('/'): { 
    std::cout << x/y << "\n"; 
    } 
    default: { 
    std::cout << "Wrong sign input. Choose on of the following four:+-*/\n"; 
    } 
    } 
} 

第二个确实只有一个工作了,也有缺陷,例如,如果输入的是“5”,“6”和“ - ”,它会返回-1,它会通过一个错误处理呼叫者,召集者。

int calculate(int x, int y, char s) { 
    switch (s) { 
    case ('+'): { 
    return x + y; 
    } 
    case ('-'): { 
    return x - y; 
    } 
    case ('*'): { 
    return x * y; 
    } 
    case ('/'): { 
    return x/y; 
    } 
    default: { 
    return -1; 
    } 
    } 
} 

你会在给定的情况下做什么?

+5

*并且由主叫方将其作为错误处理。*然后修复主叫方。恕我直言第二个功能应该使用。计算和打印应该是分开的。 – NathanOliver

+3

二是最好,错误时抛出异常。 –

+0

那么如何判断-1结果和-1错误? – KOKO

回答

0

输出和计算应该是单独的函数。但是,如果它也可以是有效的输出值,则不应使用特殊的哨兵值来指示错误。

真正的问题是,输入验证和计算应该是不同的功能。我会给潜在操作的enum,并把它传递。

enum class Operation { 
    ADD, 
    SUBTRACT, 
    MULTIPLY, 
    DIVIDE 
}; 

然后让calculate参加一次Operation。你仍然需要验证输入的地方,但它不应该在同一个地方。

您仍然需要一个default情况calculate,因为enum S能比他们的声明之外的其他价值,但因为你要验证输入的其他地方你可以把它简单的assert

2

您可以使用返回值来返回操作的结果或状态码,但不能同时使用(除非您使用特殊值,我将避免使用这些值。)如何使用状态的返回值,并将结果设置为输出参数?

int calculate(int x, int y, char s, int & result); // returns: 0 - success; -1 - failure 
+0

像这样的输出参数通常很难使用,虽然这可能工作。 –

+1

反过来也是可能的 - 使用结果的返回值,状态的输出参数 - 根据用例 – gcbenison

+0

@gcbenison我可以这么说。错误代码返回被忽略的风险。很难忽视必要的参考。虽然不是太难以忽视并丢弃... – Persixty

1

你有几个更好的选择。

  1. 抛出一个异常
  2. 返回std::numeric_limits<int>::max()
  3. 将实际结果通过指针/引用传递的变量,并使用返回值状态

我会去例外。

default: 
    throw std::invalid_argument(std::string("invalid operator: ") + s); 
+1

4.返回一个不同的类型,5. assert(非常类似于抛出异常,如果KOKO不知道如何捕捉异常),6. * accept *一个不同的类型('enum class Operation')并在一个单独的函数中进行输入验证。我会做6;验证和计算不应该是相同的功能。 –

+0

我喜欢'enum class Operation'。这使得更好的界面。 – crazypeter

1

首先,将计算与输出计算结果分开是一个好主意。

来到的如何处理错误输入的问题...

另一种方法能够返回的状态和结果将是使用std::pair作为返回类型。

std::pair<bool, int> calculate(int x, int y, char s) 
{ 
    ... 
} 

,并确保返回{true, result}的成功案例和不成功的情况下返回{false, 0}

+0

这看起来很酷。 – KOKO

+0

更好的解决方案是'std :: optional',但你的编译器可能还不支持。 –

0

编辑:

处理错误的正确方法是抛出和捕获。这是它的一个版本。

#include <iostream> 
#include <stdexcept> 
using std::cout; 
using std::cin; 
using std::cerr; 
using std::invalid_argument; 

int calculate(int, int, char); 

int main() 
{ 
    int num1, num2; 
    char symbol; 
    cin >> num1 >> num2 >> symbol; 
    try { 
     cout << calculate(num1,num2,symbol) << '\n'; 
    } catch (const invalid_argument& error) { 
     cout << error.what() << '\n'; 
     return 1; 
    } 
    return 0; 
} 

int calculate(int x, int y, char s) { 
switch (s) { 
    case '+': 
     return x + y; 

    case '-': 
     return x - y; 

    case '*': 
     return x * y; 

    case '/': 
     return x/y; 

    default: 
     throw invalid_argument("Received non existing option!"); 
} 
} 

此外,这里是一个没有抛出的版本。

这是您的代码的工作版本。

#include <iostream> 
using std::cout; 
using std::cin; 
using std::cerr; 

int calculate(int, int, char); 

int main() 
{ 
    int num1, num2; 
    char symbol; 
    cin >> num1 >> num2 >> symbol; 
    cout << calculate(num1,num2,symbol) << '\n'; 
    return 0; 
} 

int calculate(int x, int y, char s) { 
switch (s) { 
    case '+': 
     return x + y; 

    case '-': 
     return x - y; 

    case '*': 
     return x * y; 

    case '/': 
     return x/y; 

    default: 
     cerr << "Unrecognised option!\n"; 
     return -1; 
} 
} 

我已经改变格式化了一点。随意探索它,如果您有任何与代码有关的问题,请问。

对问题的回答:更喜欢第二种方式。这是正确的方法。

+0

问题在于,即使输入正确,函数也可以返回-1。此外,如果它通过默认它将打印-1 ?! – KOKO

+0

我知道,但如果这是错误,它也会说无法识别的选项! 让我们试试。 5 6 - 给了我一个-1。 5 6)给了我一个无法识别的选项! -1正确的方法是抛出,但你说它已经回到了你的教程中。现在你可以指定错误信息。 –

+0

我明白你的观点。 – KOKO