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 declarationsusing指令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;
}

image

解决方案
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;
}

image

显示答案

#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() 函数存在哪些不足之处?

显示方案

  1. 没有常规方法可以在不重启程序的情况下重置累加值。
  2. 没有常规方法可以同时运行多个累加器。

对于进阶读者
这两个缺陷都可以通过使用函子(参见21.10节——重载括号运算符)来解决,而非依赖静态局部变量。

posted @ 2026-02-23 16:57  游翔  阅读(0)  评论(0)    收藏  举报