7-x 第七章总结与测验
章节回顾
本章内容涵盖广泛。干得漂亮,你做得很好!
复合语句compound statement或代码块block是由零个或多个语句组成的集合,编译器将其视为单个语句处理。代码块以{符号开头,以}符号结束,需执行的语句置于其间。代码块可在允许单个语句的任何位置使用,且末尾无需分号。代码块常与if语句配合使用以执行多条语句。
用户定义的命名空间User-defined namespaces是指您为自身声明定义的命名空间。C++ 提供的命名空间(如全局命名空间)或库提供的命名空间(如命名空间 std)不被视为用户定义的命名空间。
可通过作用域解析运算符(::)scope resolution operator (::)访问命名空间内的声明。该运算符告知编译器:应在左操作数的范围内查找右操作数指定的标识符。若未提供左操作数,则默认在全局命名空间中查找。
局部变量是在函数内部定义的变量(包括函数形参)。局部变量具有块作用域block scope,即从定义点到所属块结尾均有效。局部变量具有自动存储期automatic storage duration,即在定义点创建并在所属块结尾销毁。
在嵌套代码块中声明的变量可能遮蔽shadow或者名称隐藏name hide外部代码块中同名变量。应避免此类情况。
全局变量是在函数外部定义的变量。全局变量具有文件作用域file scope,即从声明点到声明文件结尾均可见。全局变量具有静态存储期static duration,即程序启动时创建,程序结束时销毁。应尽可能避免对静态变量进行动态初始化。
标识符的链接linkage决定了其他同名声明是否指向同一对象。局部变量不具有链接。具有内部链接internal linkage的标识符可在单个文件内被访问和使用,但无法从其他文件访问。具有外部链接external linkage的标识符既可在定义文件内被访问和使用,也可通过前向声明从其他代码文件访问和使用。
尽可能避免使用非const全局变量。const全局变量通常被视为可接受。若编译器支持C++17,可使用内联变量inline variables替代全局常量。
局部变量可通过static关键字赋予静态存储期。
限定名qualified name包含关联作用域(如std::string),非限定名unqualified name则不含作用域限定符(如string)。
using语句Using statements(包括using声明using declarations和using指令using directives)可避免显式命名空间限定。using声明using declaration允许将非限定名称(无作用域)作为限定名称的别名;using指令using directive则将命名空间内所有标识符导入指令作用域。通常应避免使用这两种方式。
内联展开Inline expansion是指用被调函数定义中的代码替换函数调用的过程。使用inline关键字声明的函数称为内联函数inline function。
内联函数与变量需满足两项核心要求:
- 编译器必须能在函数使用的每个翻译单元中看到其完整定义(仅前向声明不足以满足要求)。若同时提供前向声明,定义可出现在使用点之后。
- 所有内联函数或变量的定义必须完全一致,否则将导致未定义行为。
在现代C++中,inline一词已演变为“允许多重定义”之意。因此内联函数是指允许在多个文件中定义的函数。C++17引入了内联变量inline variables,即允许在多个文件中定义的变量。
内联函数和变量对纯头文件库header-only libraries尤为重要——这类库仅由实现特定功能的头文件构成(不含.cpp文件)。
最后,C++支持无名命名空间unnamed namespaces,其隐式将命名空间内所有内容视为具有内部链接。C++还支持内联命名空间inline namespaces,为命名空间提供基础版本控制功能。
测验时间
问题 #1
修复以下程序:
#include <iostream>
int main()
{
std::cout << "Enter a positive number: ";
int num{};
std::cin >> num;
if (num < 0)
std::cout << "Negative number entered. Making positive.\n";
num = -num;
std::cout << "You entered: " << num;
return 0;
}
显示方案
#include <iostream>
int main()
{
std::cout << "Enter a positive number: ";
int num{};
std::cin >> num;
if (num < 0)
{ // block needed here so both statements execute if num is < 0
std::cout << "Negative number entered. Making positive.\n";
num = -num;
}
std::cout << "You entered: " << num;
return 0;
}
问题 #2
编写一个名为 constants.h 的文件,使以下程序能够运行。如果您的编译器支持 C++17,请使用内联 constexpr 变量;否则,请使用常规 constexpr 变量。maxClassSize 的值应为 35。
main.cpp:
#include "constants.h"
#include <iostream>
int main()
{
std::cout << "How many students are in your class? ";
int students{};
std::cin >> students;
if (students > Constants::maxClassSize)
std::cout << "There are too many students in this class";
else
std::cout << "This class isn't too large";
return 0;
}

解决方案
constants.h:
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace Constants
{
inline constexpr int maxClassSize{ 35 }; // remove inline keyword if not C++17 capable
}
#endif
main.cpp:
#include "constants.h"
#include <iostream>
int main()
{
std::cout << "How many students are in your class? ";
int students{};
std::cin >> students;
if (students > Constants::maxClassSize)
std::cout << "There are too many students in this class";
else
std::cout << "This class isn't too large";
return 0;
}
问题 #3
编写一个函数 int accumulate(int x)。该函数应返回所有传递给此函数的 x 值的总和。
显示提示
提示:使用静态局部变量来存储求和结果。
以下程序应能运行并产生注释中注明的输出:
#include <iostream>
int main()
{
std::cout << accumulate(4) << '\n'; // prints 4
std::cout << accumulate(3) << '\n'; // prints 7
std::cout << accumulate(2) << '\n'; // prints 9
std::cout << accumulate(1) << '\n'; // prints 10
return 0;
}

显示答案
#include <iostream>
int accumulate(int x)
{
static int sum{ 0 }; // initialize sum to 0 at start of program
sum += x;
return sum;
}
int main()
{
std::cout << accumulate(4) << '\n'; // prints 4
std::cout << accumulate(3) << '\n'; // prints 7
std::cout << accumulate(2) << '\n'; // prints 9
std::cout << accumulate(1) << '\n'; // prints 10
return 0;
}
3b) 附加题:上述 accumulate() 函数存在哪些不足之处?
显示方案
- 没有常规方法可以在不重启程序的情况下重置累加值。
- 没有常规方法可以同时运行多个累加器。
对于进阶读者
这两个缺陷都可以通过使用函子(参见21.10节——重载括号运算符)来解决,而非依赖静态局部变量。

浙公网安备 33010602011771号