【问题标题】:Using cin/cout streams in functions [closed]在函数中使用 cin/cout 流
【发布时间】:2015-09-17 05:17:03
【问题描述】:

我在学校被教导说,使用cin/cout 在函数中获取并向用户显示信息被认为是不好的做法。有人告诉我所有输入/输出都应该在main 函数中完成。

这是真的吗?为什么?

【问题讨论】:

  • 这通常是个坏主意,尤其是在数据结构中的插入或删除函数中。如果你这样做了,你应该传递一个输入/输出,这样它就不会将输入/输出绑定到可能不会被使用或预期的资源。
  • 您可以参考this 了解如何操作...
  • 视情况而定。仅用于获取输入的特殊功能呢?记录功能呢? 在某些情况下不建议这样做,但根据您的程序及其要求,这些情况会有所不同。
  • @RSahu:它不适合程序员。它既过于宽泛,而且主要基于意见。

标签: c++


【解决方案1】:

对于学校来说,这是一种过于简单化的做法。真正的意思可能是那个

输入/输出应与数据处理分开。

这很容易通过一个例子来说明:

错误:

void doStuff() {
    std::string input;
    std::cout << "Please provide input: ";
    std::cin >> input;

    for (int i = 0; i < input.size(); i += 2) {
        input[i] = ' ';
    }

    std::cout << input << std::endl;
}

int main() {
    doStuff();
}

好多了:

std::string getInput() { 
    std::string input;
    std::cin >> input;
    return input;
}

std::string processData(std::string input) {
    for (int i = 0; i < input.size(); i += 2) {
        input[i] = ' ';
    }
    return std::move(input);
}

void printOutput(std::string const& s) {
    std::cout << s << std::endl;
}

int main() {
    auto input = getInput();
    auto output = processData(input);
    printOutput(output);
}

通过这种方式,您可以轻松地分别模拟或测试每个函数,并且现在添加输入验证等更加容易。

std::string getInput() { 
    std::string input;
    if (!(std::cin >> input)) {
        throw std::runtime_error("Input problem!");
    }

    if (input.empty()) {
        throw std::length_error("Input can't be empty!");
    }

    return input;
}

作为旁注,main 也可以写成:

int main () {
    printOutput(processData(getInput()));
}

【讨论】:

  • 我会从中删除“很多”。在没有重定向的情况下将所有输入概括为std::cin 似乎相当有限。恕我直言,您可以轻松地将流传递给输入函数并制作“非常”更灵活的解决方案。
【解决方案2】:

你的老师最有可能是防止类似的代码

void add(void) {
  int a, b;
  cin >> a >> b;
  cout << (a + b) << endl;
}

这是初学者程序员经常看到的。这段代码的坏处在于,它一方面谎报自己做了什么(因为它不添加,它读取、添加和打印),另一方面另一方面滥用了最重要的抽象工具,函数:

函数旨在解决 一个 任务(可能很复杂并且由子任务组成)并且更多地保留了该术语的数学起源 - 充当某种给定的转换某些结果的参数,理想情况下就像在纯函数式语言中一样,而不会改变我们的任何状态。 (无论何时、多久以及在何种情况下调用f(a),如果您曾经得到b,那么每次使用a 调用f 时都会得到)

将其应用于简单示例给出

int add(int lhs, int rhs) {
  return lhs + rhs;
}

尽管如此,我们还是需要以某种方式访问​​现实世界(这是非常有状态的),因此对于以下情况,可以在函数中使用 IO:

int askInteger(void) {
  int result;
  cout << "Please give me an integer!";
  cin >> result;
  return result;
}

请注意,这只是一个相对愚蠢的例子,没有任何错误处理或参数化。

为了更接近函数式风格,建议不要像上面那样对 IO 的源和目标进行硬编码,而是将它们作为参数传递:

int askInteger(std::istream & from, std::ostream & to) {
  int result;
  to << "Please give me an integer!";
  from >> result;
  return result;
}
// called like
askInteger(cin, cout);

【讨论】:

  • 亲爱的投票者,请解释我的答案的哪一部分应该改进。
猜你喜欢
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多