Skip to content

2.6 - 为什么函数有用,如何高效使用函数

通过前面的学习,我们已经了解了什么是函数以及函数的基本功能,接下来,让我们看看,为什么说函数非常有用。

函数为什么有用

新手程序员总会问:“难道我们就不能把所有的代码都塞到 main 函数里面吗?” ,其实对于非常简单的程序,你的确可以将所有的代码都塞到 main 函数里面。但是,对于代码量比较多或复杂度较高的程序来说,使用函数能够带来很多好处:

  • 便于组织代码 -- 随着程序的复杂性越来越高,将所有的代码都是塞到main函数中会使 main 函数变得非常复杂。我们可以将函数看做是一个个独立于主程序的迷你程序,在编写它们的时候我们无需考虑其他程序。这样,我们就可以将一个复杂的程序简化为多个更小、更易维护的段落,从而降低整个程序的复杂度;
  • 提高可重用性 -- 当函数被编写后,它可以在程序中被多次调用。这么做可以避免重复代码 (“Don’t Repeat Yourself”原则)而且能够最大程度上减少复制粘贴代码所可能带来的错误。函数还可以在程序间共享,这么做可以避免重复编写(或测试)代码。;
  • 便于测试代码 -- 函数可以减少冗余代码,因此首先就可以减少需要测试的代码数量。同时,由于函数是自包含的,因此当函数通过测试并确保正确工作后,除非它被修改了,否则将无需对其进行测试。这么做显然可以减少很多需要测试的代码,发现bug的难度也就随之降低了(也更加容易避免bug);
  • 提高可扩展性 -- 当我们需要对程序进行扩展,以使其能够处理之前不能处理的情况时,函数能够使我们在一处进行改动并将改动的效果应用到所有调用了该函数的地方;
  • 提高抽象程度 -- 为了使用某个函数,你必须知晓其函数名、输入、输出以及它所处的位置。但是,你不必知道它如何工作或者任何与使用其功能不相干的信息。这样一来,在使用他人的代码(或者任何标准库中的函数)时,你的认知负载就降低了。

尽管看上去不像,但实际上每当你使用 operator<<operator>> 运算符时,你实际上在使用标准库提供的一个函数,它同样具有上述全部的优点。

高效地使用函数

新手程序员遇到的(除了学习语言本身)最大挑战便是理解何时,以及如何高效地使用函数。下面是一些关于编写函数的指导原则:

  • 在程序中重复出现的一组语句,通常可以被封装成一个函数。例如,如果你使用同样的方式多次从用户那里获取输入,那么这些重复代码就很适合被封装成函数。如果我们以同样的形式在多处进行输出,这同样也是非常适合封装函数的情景;
  • 明确定义了输入和输出的代码非常适合封装成函数(尤其是当这些代码非常复杂的时候)。例如,如果我们有一个需要排序的列表,那么对其进行排序的代码就非常适合作为函数,既是该排序可能只进行依次。这种情况下,输入是一个未排序的列表,输出则是一个排序后的列表。还有很好的例子是,如果你编写了一些模拟掷骰子的程序,那么它也很适合作为函数。尽管在当前的程序中你可能只会使用它一次,但是将来如果你想扩展程序或编写其他程序,该功能就可以直接被复用;
  • 一个函数应该只做一件事;
  • 如果一个函数变得又长、又复杂、或者难以理解了,那么它就应该被再次拆分,变成几个子函数。这个过程称为重构(refactoring) 。我们会在3.10 - 在问题发生前发现问题中介绍重构的概念。

通常,在学习C++的时候,你编写的很多程序都涉及到如下三种类型的子任务:

  1. 从用户获取输入;
  2. 基于输入进行计算;
  3. 打印计算的结果。

对于短小的程序 (例如,小于20行代码的程序),上述三个子任务都可以在 main 函数中完成。然而,对于更长(或者出于练习的目的),上述三个任务都很适合各自作为一个单独的函数。

新手程序员通常会将计算结果和打印结果这两步合并为一个函数。不过,这么做违反了“一个函数只做一件事” 的原则。负责计算结果的函数应该将结果返回给主调函数,然后让主调函数决定如何使用该返回值(例如调用另外一个函数将该结果打印出来)。