6.1. 简单语句
C++ 中,大多数语句以分号结束。例如,像 ival + 5 这样的表达式,在后面加上分号,就是一条表达式语句。
表达式语句用于计算表达式。
但执行下面的语句
ival + 5; // expression statement
却没有任何意义:
因为计算出来的结果没有用于赋值或其他用途;
1. 空语句
程序语句最简单的形式是空语句,它使用以下的形式(只有一个单独的分号):
; // null statement
6.2. 声明语句
在 C++ 中,对象或类的定义或声明也是语句。
尽管定义语句这种说法也许更准确些,但定义语句经常被称为声明语句;
6.3. 复合语句(块)
复合语句,通常被称为块,是用一对花括号括起来的语句序列(也可能是空的)。
块标识了一个作用域,在块中引入的名字只能在该块内部或嵌套在块中的子块里访问。
通常,一个名字只从其定义处到该块的结尾这段范围内可见。
复合语句用在语法规则要求使用单个语句但程序逻辑却需要不止一个语句的地方
6.4. 语句作用域
有些语句允许在它们的控制结构中定义变量:
while (int i = get_num())
cout << i << endl;
i = 0; // error: i is not accessible outside the loop
在条件表达式中定义的变量必须初始化,该条件检验的就是初始化对象的值。
在语句的控制结构中定义的变量,仅在定义它们的块语句结束前有效。
6.5. if 语句
if 语句根据特定表达式是否为真来有条件地执行另一个语句。
if 语句有两种形式:
其中一种带 else 分支而另一种则没有。
根据语法结构,最简单的 if 语句是这样的:
if (condition)
statement
6.5.1. if 语句的 else 分支
if else 语句的语法形式为:
if (condition)
statement1
else
statement2
6.6. switch 语句
6.6.1. 使用 switch
6.6.2. switch 中的控制流
了解 case 标号的执行流是必要的。
存在一个普遍的误解:以为程序只会执行匹配的 case 标号相关联的语句。
实际上,程序从该点开始执行,并跨越 case 边界继续执行其他语句,直到 switch 结束或遇到 break 语句为止。
6.6.3. default 标号
default 标号提供了相当于 else 子句的功能。
如果所有的 case 标号与switch 表达式的值都不匹配,并且 default 标号存在,
则执行 default 标号后面的语句。
6.6.4. switch 表达式与 case 标号
switch 求解的表达式可以非常复杂
6.7. while 语句
当条件为真时,while 语句反复执行目标语句。它的语法形式如下:
while (condition)
statement
6.8. for 循环语句
for 语句的语法形式是:
for (init-statement condition; expression)
statement
init-statement 必须是声明语句、表达式语句或空语句。这些语句都以分号结束,
因此其语法形式也可以看成:
for (initializer; condition; expression)
statement
6.9. do while 语句
do
statement
while (condition);
6.10. break 语句
break 语句用于结束最近的 while、do while、for 或 switch 语句,
并将程序的执行权传递给紧接在被终止语句之后的语句。
6.11. continue 语句
continue 语句导致最近的循环语句的当次迭代提前结束。
对于 while 和do while 语句,继续求解循环条件。
而对于 for 循环,程序流程接着求解 for语句头中的 expression 表达式。
continue 语句只能出现在 for、while 或者 do while 循环中,
包括嵌套在这些循环内部的块语句中。
6.12. goto 语句
goto 语句提供了函数内部的无条件跳转,实现从 goto 语句跳转到同一函数内某个带标号的语句。
goto 语句的语法规则如下:
goto label;
其中 label 是用于标识带标号的语句的标识符。
在任何语句前提供一个标识符和冒号,即得带标号的语句
6.13. try 块和异常处理
C++ 的异常处理中包括:
1. throw 表达式,
错误检测部分使用这种表达式来说明遇到了不可处理的错误。
可以说,throw 引发了异常条件。
2. try 块,错误处理部分使用它来处理异常。
try 语句块以 try 关键字开始,并以一个或多个 catch 子句结束。
在 try 块中执行的代码所抛出(throw)的异常,通常会被其中一个 catch 子句处理。
由于它们“处理”异常,catch 子句也称为处理代码。
3. 由标准库定义的一组异常类,用来在 throw 和相应的 catch 之间传递有关的错误信息。
6.13.1 throw 表达式
系统通过 throw 表达式抛出异常。
throw 表达式由关键字 throw 以及尾随的表达式组成,通常以分号结束,这样它就成为了表达式语句。
throw 表达式的类型决定了所抛出异常的类型。
// first check that data is for the same item
if (!item1.same_isbn(item2))
throw runtime_error("Data must refer to same ISBN");
// ok, if we're still here the ISBNs are the same
std::cout << item1 + item2 << std::endl;
这段代码检查 ISBN 对象是否不相同。
如果不同的话,停止程序的执行,并将控制转移给处理这种错误的处理代码。
6.13.2. try 块
try 块的通用语法形式是:
try {
program-statements
} catch (exception-specifier) {
handler-statements
} catch (exception-specifier) {
handler-statements
} //...
try 块以关键字 try 开始,后面是用花括号起来的语句序列块。
try 块后面是一个或多个 catch 子句。
每个 catch 子句包括三部分:
关键字 catch,
圆括号内单个类型或者单个对象的声明——称为异常说明符,
以及通常用花括号括起来的语句块。
如果选择了一个 catch 子句来处理异常,则执行相关的块语句。
一旦 catch 子句执行结束,程序流程立即继续执行紧随着最后一个 catch 子句的语句。
try 语句内的 program-statements 形成程序的正常逻辑。
这里面可以包含任意 C++ 语句,包括变量声明。
与其他块语句一样,try 块引入局部作用域,
在 try 块中声明的变量,包括 catch 子句声明的变量,不能在 try 外面引用。
6.13.3. 标准异常
C++ 标准库定义了一组类,用于报告在标准库中的函数遇到的问题。
程序员可在自己编写的程序中使用这些标准异常类。
标准库异常类定义在四个头文件中:
1. exception 头文件定义了最常见的异常类,它的类名是 exception。
这个类只通知异常的产生,但不会提供更多的信息。
2. stdexcept 头文件定义了几种常见的异常类,这些类型在表 6.1 中列出。
表 6.1 在 头文件中定义的标准异常类
exception 最常见的问题。
runtime_error 运行时错误:仅在运行时才能检测到问题
range_error 运行时错误:生成的结果超出了有意义的值域范围
overflow_error 运行时错误:计算上溢
underflow_error 运行时错误:计算下溢
logic_error 逻辑错误:可在运行前检测到问题
domain_error 逻辑错误:参数的结果值不存在
invalid_argument 逻辑错误:不合适的参数
length_error 逻辑错误:试图生成一个超出该类型最大长度的对象
out_of_range 逻辑错误:使用一个超出有效范围的值
标准库异常类
标准库异常类只提供很少的操作,包括创建、复制异常类型对象以及异常类型对象的赋值。
6.14. 使用预处理器进行调试
第 2.9.2 节介绍了如何使用预处理变量来避免重复包含头文件。C++ 程序
员有时也会使用类似的技术有条件地执行用于调试的代码。这种想法是:程序所
包含的调试代码仅在开发过程中执行。当应用程序已经完成,并且准备提交时,
就会将调试代码关闭。可使用 NDEBUG 预处理变量实现有条件的调试代码:
int main()
{
#ifndef NDEBUG
cerr << "starting main" << endl;
#endif
// ...
}
如果 NDEBUG 未定义,那么程序就会将信息写到 cerr 中。
如果 NDEBUG 已经定义了,那么程序执行时将会跳过 #ifndef 和 #endif 之间的代码。
默认情况下,NDEBUG 未定义,这也就意味着必须执行 #ifndef 和 #endif之间的代码。
在开发程序的过程中,只要保持 NDEBUG 未定义就会执行其中的调试语句。
开发完成后,要将程序交付给客户时,可通过定义 NDEBUG 预处理变量,
(有效地)删除这些调试语句。
大多数的编译器都提供定义 NDEBUG 命令行选项:
$ CC -DNDEBUG main.C
这样的命令行行将于在 main.c 的开头提供 #define NDEBUG 预处理命令。
预处理器还定义了其余四种在调试时非常有用的常量:
__FILE__ 文件名
__LINE__ 当前行号
__TIME__ 文件被编译的时间
__DATE__ 文件被编译的日期
可使用这些常量在错误消息中提供更多的信息:
if (word.size() < threshold)
cerr << "Error: " << _ _FILE_ _
<< " : line " << _ _LINE_ _ << endl
<< " Compiled on " << _ _DATE_ _
<< " at " << _ _TIME_ _ << endl
<< " Word read was " << word
<< ": Length too short" << endl;
如果给这个程序提供一个比 threshold 短的 string 对象,则会产生下面的错误信息:
Error: wdebug.cc : line 21
Compiled on Jan 12 2005 at 19:44:40
Word read was "foo": Length too short
阅读(1058) | 评论(0) | 转发(0) |