第2章总结
本节阅读量:章节回顾
函数是一个可重用的语句序列,旨在完成特定的工作。自己编写的函数称为用户定义函数。
函数调用是一个告诉CPU去执行某个函数的表达式。发起函数调用的函数是调用者,而被调用的函数则是被调用者或被调用函数。进行函数调用时,记得要带括号。
函数定义中的花括号和语句称为函数体。
函数的返回类型指示函数将返回什么类型的值。return语句确定返回给调用方的具体返回值。返回值从函数复制给调用者——此过程称为按值返回。返回类型非void的函数,如果未指定返回值,将导致未定义的行为。
函数main的返回值称为状态码,用来告诉操作系统(以及调用程序的任何其他程序)程序是否成功执行。根据共识,返回值0表示成功,非零返回值表示失败。
践行DRY(Don’t Repeat Yourself)编程——“不要重复自己”。利用变量和函数来消除冗余代码。
返回类型为void的函数不向调用方返回值。不返回值的函数称为void函数。在需要返回值的地方不能调用void函数。
函数执行return语句时会立即返回给调用方,即使这不是函数中的最后一条语句。
函数参数是函数中使用的变量,其值由函数的调用方提供。将参数的值复制给对应的函数参数,称为按值传递。
函数体中定义的函数参数和变量称为局部变量。变量实例存在的时间称为其生命周期。变量在运行时被创建和销毁。变量的作用域决定了它可以在哪里被看到和使用。当一个变量可以被看到和使用时,我们说它在作用域内。当不可见时,就不能使用,即它超出了作用域。作用域是编译时属性,意味着在编译时强制检查。
前向声明允许在实际定义标识符之前告诉编译器该标识符的存在。为了编写函数的前向声明,我们使用函数原型,其中包括函数的返回类型、名称和参数,但没有函数体,后面跟着分号。
定义是实际实现(对于函数和类型)或实例化(对于变量)标识符的语句。声明是告诉编译器标识符存在的语句。在C++中,所有定义都是声明。纯声明则是不属于定义的声明(例如函数原型)。
大多数有价值的程序都包含多个文件。
当两个标识符以编译器或链接器无法区分的方式引入同一程序时,编译器或链接器将因命名冲突而报错。命名空间保证其中的所有标识符都是唯一的。std命名空间就是这样一个命名空间。
预处理器是在编译代码之前对代码进行处理的程序。预处理指令是预处理器的特殊指令。预处理指令以#符号开头,以换行符结尾。宏是定义如何将输入文本转换为替换输出文本的规则。
头文件是用于将声明传播到代码文件的文件。使用#include指令时,#include指令会被对应文件的内容替换。引用头文件时,系统头文件(例如C++标准库中的头文件)使用尖括号,用户定义的头文件使用双引号。
头文件保护可防止同一头文件的内容被重复包含到同一个代码文件中。但不会阻止头文件的内容被包含到多个不同的代码文件中。
习题
请务必使用编辑器的自动格式化功能,保持格式一致,让代码更易读。
问题 1
编写一个单文件程序(文件名为 main.cpp):从用户处分别读取两个整数,将它们相加,然后输出结果。程序应当使用三个函数:
- 名为「readNumber」的函数负责从用户处获取(并返回)一个整数。
- 名为「writeAnswer」的函数负责输出结果。该函数接受一个形参,并且没有返回值。
main()函数负责把上面两个函数串起来。
显示提示
不必为相加单独写一个函数(直接使用operator+即可)。
显示提示
你需要调用两次readNumber()。
查看答案
main.cpp:
|
|
问题 2
修改你在第1题中编写的程序,让readNumber()与writeAnswer()位于一个单独的文件「io.cpp」中。使用前向声明,以便在main()中访问它们。
如果遇到问题,请确认「io.cpp」已经正确地添加到项目中,从而能够被编译。
查看答案
io.cpp:
|
|
main.cpp:
|
|
问题 3
修改你在第2题中编写的程序,改为使用一个头文件(名为 io.h)来访问这些函数,而不是直接在 .cpp 文件中写前向声明。请确保头文件中使用了头文件保护。
查看答案
io.h:
|
|
io.cpp:
|
|
main.cpp:
|
|
严格来说,io.cpp 并不需要包含 io.h,但让代码文件包含与之配套的头文件是一个最佳实践。这一点在「2.10 头文件」中会讲到。
如果编译程序时出现下列这样的错误:
unresolved external symbol "int __cdecl readNumber(void)" (?readNumber@@YAHXZ)
undefined reference to `readNumber()'
那多半是忘记把 io.cpp 加入项目了,因此readNumber()(以及writeAnswer())的定义没有被编译进项目。