我试着去理解OOP,想知道我的函数是否完成得正确

Trying to get my head around OOP and wondering if my functions are done correctly

本文关键字:是否 函数 我的 想知道 OOP      更新时间:2023-10-16

我正在制作一个简单的小型计算器应用程序,我想知道如何最好地将封装和抽象结合到代码中,使其整洁有序。

这是如何使用以下代码处理这些方法的理想方法吗?我不确定它是否有点过火,但在我看来,它让它非常可读和整洁。

还有一条规则是,如果你在重复代码,它就属于一个函数吗?

提前谢谢。

// Test ApplicationV2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>


int getNumber();
char getOperation();
int additionResult(int& val1, int& val2);
int multiplyResult(int& val1, int& val2);
int divisionResult(int& val1, int& val2);
int main()
{
    int val1, val2;
    char operation;
    std::cout << "Enter the first value.";
    val1 = getNumber();
    std::cout << "Enter operation";
    operation = getOperation();
    std::cout << "Enter second number.";
    val2 = getNumber();
    switch (operation)
    {
    case '+':
        std::cout << additionResult(val1, val2);
        break;
    case '*':
        std::cout << multiplyResult(val1, val2);
        break;
    case '/':
        std::cout << divisionResult(val1, val2);
        break;
    default:
        std::cout << "Please enter sufficient data.";
    }
    //Keep window open
    std::string barn;
    std::cin >> barn;
    return 0;
}
int getNumber()
{
    int x;
    std::cin >> x;
    return x;
}
char getOperation()
{
    char op;
    std::cin >> op;
    return op;
}
int additionResult(int& val1, int& val2)
{
    return (val1 + val2);
}
int multiplyResult(int& val1, int& val2)
{
    return (val1 * val2);
}
int divisionResult(int& val1, int& val2)
{
    return (val1 / val2);
}

如上所述,您的程序不使用OOP(除非std::coutstd::cin是对象)。如果您的目标是探索使用OOP作为构建代码的一种方式,那么可以考虑:

#include <iostream>
class Calculation
{
  public:
    Calculation(int first, int second)
      : first_(first), second_(second)
    { }
    int add() { return first_ + second_; }
    int multiply() { return first_ * second_; }
    int divide() { return first_ / second_; }
  private:
    int first_, second_;
};
int main()
{
    int val1, val2;
    char operation;
    if (std::cout << "Enter the first value: " &&
        std::cin >> val1 &&
        std::cout << "Enter operation: " &&
        std::cin >> operation &&
        std::cout << "Enter the second value: " &&
        std::cin >> val2)
    {
        Calculation calc(val1, val2);
        switch (operation)
        {
          case '+':
            std::cout << calc.add() << 'n';
            break;
          case '*':
            std::cout << calc.multiply() << 'n';
            break;
          case '/':
            std::cout << calc.divide() << 'n';
            break;
          default:
            std::cerr << "Invalid operator: must be +, * or /.n";
        }
    }
    else
        std::cerr << "Error getting inputs.n";
    //Keep window open
    std::cin.get();  // real operating systems don't need this ;-P
}

注意,Calculation类是OOP方面,它有private数据:这是封装。虽然它没有太多抽象——问题太简单了——但你可以说它捕获了构造时的输入和add()multiply()divide()调用不必知道所涉及的数据的类型或数量(即,Calculator可能存储了std::vector<int>double,并且switch语句的代码不需要更改,前提是这三个函数的返回类型存在operator<<重载)。

您可以通过在Calculation中拥有一个成员函数来获得更多的抽象,比如:

int do_operation(char c) const
{
    switch (c)
    {
      case '+': return first_ + second_;
      case '*': return first_ * second_;
      case '/': return first_ / second_;
      default: throw std::runtime_error("invalid operator character");
    }
}

然后main的使用可以尝试一个操作,看看它是否受支持,而不知道Calculation:提供的确切操作

Calculation calc(val1, val2);
try
{
    std::cout << calc.do_operation(operation) << 'n';
}
catch (const std::exception& e)
{
    std::cerr << "oops - caught exception: " << e.what() << 'n';
}

这似乎没什么大不了的,但这意味着,如果您有很多地方使用Calculation对象,那么当您想要支持另一个操作时,就不必全部更新它们。缺点是CCD_ 17的返回类型对于所有类型的操作都必须相同,因此,您不能决定"嘿,我将使用除法返回double,而不是四舍五入到int",只需更改divide()的返回类型即可(但您可以让它们都返回double-在这种简单的情况下不会造成太大伤害,更普遍的情况是,您可以使用"variant"返回一组类型中的任何一个,但客户端代码更难使用它们)。

还有一条规则是,如果你在重复代码,它就属于一个函数吗?

差不多。请注意,您没有重复(调用两次)放入函数中的任何代码,但这在更复杂的程序中变得很重要。

作为使用函数分解上述代码的一个示例,请考虑如何将提示和输入组合到可重用函数中:

template <typename T>
bool input(const std::string& prompt, T& value)
{
    return std::cout << prompt && std::cin >> value;
}

template <typename T>意味着上述函数可以与任何类型的value一起工作。使用这个input功能,提示和输入操作可以重写为:

if (input("Enter the first value: ", val1) &&
    input("Enter operation: ", operation) &&
    input("Enter the second value: ", val2))
{

这是否更好取决于读者是否能够猜测input做得足够好,不需要去研究input函数,但它被重复使用的频率越高,即使这样的努力也越有可能是值得的。

一种可能性是有一个抽象的"二进制运算"类,然后为每个实际运算(加法、减法、乘法、除法)都有派生类。

如果您这样做,您就可以(例如)创建一个包含(指向)二进制操作对象的指针或引用的容器,并在该集合中查找正确的操作。例如:

struct bin_op { 
    virtual int operator()(int a, int b);
};
struct add : bin_op { 
    virtual int operator()(int a, int b) { return a + b; }
};
struct sub : bin_op {
    virtual int operator()(int a, int b) { return a - b; }
};
// mul and div similarly.
std::map<char, bin_op *> ops;
add a;
sub s;
mul m;
div d;
ops['+'] = &a;
ops['-'] = &s;
ops['*'] = &m;
ops['/'] = &d;

然后要执行操作,您可以执行以下操作:

auto b = ops.find(operation);
if (b != ops.end())
    std::cout << b->second(val1, val2);
else
    std::cerr << "unknown operation: " << operation << "n";

这样做的一个明显优点是,添加新操作非常简单:定义一个从bin_op派生的新类来执行新操作,将其实例添加到ops(带有要触发该操作的字符),然后就可以了。

相关文章: