目录
6.1 简单语句
6.2 声明语句
6.3 复合语句(块)
6.4 语句作用域
6.5 if语句
6.6 switch语句
6.7 while语句
6.8 for循环语句
6.9 do while语句
6.10 break语句
6.11 continue语句
6.12 goto语句
6.13 try块和异常处理
6.14 使用预处理器进行测试
6.1 简单语句
C++中,大多数语句以分号结束。
6.2 声明语句
6.3 复合语句
复合语句,通常被称为块,是用一对花括号括起来的语句序列。块标识了一个作用域,在块中引入的名字只能在该块内部或嵌套在块中的子块里访问。
6.4 语句作用域
有些语句允许在它们的控制结构中定义变量,但仅在定义它们的块语句结束前有效,其作用域局限在语句内部。
while (int i =get_num()) cout << i << endl; i = 0; //error: i is not accessable outside the loop
6.5 if语句
if语句的条件表达式可以是初始化声明语句,其中,变量必须初始化,因为已初始化的变更值要转换为bool值用于判断。
6.6 switch语句
6.6.1 使用switch
如果条件表达式与其中一个标号的值匹配,则程序将从该标号后面的第一个语句开始依次执行各个语句,直到switch结束或遇到break语句为止。
6.6.2 switch中的控制流
为了安全起见,最好在每个后面提供一个break语句,即使是最后一个标号也一样。如果希望省略;case后面的break语句,可以将几个case语句写在一行,可以令代码更加清晰。
6.6.3 default标号
如果所有的case标号与switch表达式的值都不匹配,并且default标号存在,则执行default标号后面的语句。
6.6.4 switch表达式与case标号
switch求解表达式可以是定义和初始化一个变量。
switch(int ival = get_response());
ival的值将要与每个case标号比较。
6.6.5 switch内部的变量定义
在switch内部,要为某个特殊的case定义变量,则可以引入块语句,在该语句中定义变量,从而保证这个变量在使用前被定义和初始化。
6.7 while语句
while循环内的赋值操作是一种常见的用法。
6.8 for循环语句
应该谨记:在for语句头定义的任何对象限制在for循环体里可见。
6.8.1 省略语句头的某些部分
可以省略初始化语句、循环语句和表达式中的任何一个,但是分号不能省略。
6.8.2 for语句头中的多个定义
可以在for语句的初始化语句中定义多个对象,但是不管怎么样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型。
6.9 do while语句
6.10 break语句
break用于结束最近的while、do while、for或switch语句,并将程序的执行权传递给紧接在被终止语句之后的语句。break只能出现在循环或switch结构中,或者出现在嵌套于循环或switch结构中的语句里。
6.11 continue语句
continue语句导致最近的循环语句的当次迭代提前结束。对于while和do while语句,继续求解循环条件,而对于for循环,程序流程接着求解for语句头中的expression表达式。
6.12 goto语句
尽量不要使用。
6.13 try块和异常处理
C++的异常处理包括:
1. throw表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误。
2. try块,错误处理部分使用它来处理异常。try语句块以try关键字开始,并以一个或多个catch子句结束。在try块中执行的代码所抛出的异常,通常会被其中一个catch子句处理。
3. 由标准库定义的一组异常类,用来在throw和相应的catch之间传递有关的错误信息。
6.13.1 throw表达式
系统通过throw表达式抛出异常。throw表达式由关键字throw以及尾随的表达式组成,通常以分号结束。
6.13.2 try块
try块的通用语法形式是:
try {
program-statements
} catch (exception-specifier) {
handler-statements
} catch (exception-specifier) {
handler-statements
}
1. 编写处理代码
2. 函数在寻找处理代码的过程中退出
寻找处理代码的过程与函数调用链刚好相反。抛出一个异常时,首先要搜索的是抛出异常的函数。如果没有找到匹配的 catch,则终止这个函数的执行,并在调用这个函数的函数中寻找相配的 catch。如果仍然找到相应的处理代码,该函数同样要终止,搜索调用它的函数。如此类推,继续按执行路径回退,直到找到适当类型的 catch 为止。
如果不存在处理该异常的 catch 子句,程序的运行就要跳转到名为 terminate 的标准库函数,该函数在 exception 头文件中定义。这个标准库函数的行为依赖于系统,通常情况下,它的执行将导致程序非正常退出。
在程序中出现的异常,如果没有经 try 块定义,则都以相同的方式来处理:毕竟,如果没有任何 try 块,也就没有捕获异常的处理代码(catch 子句)。此时,如果发生了异常,系统将自动调用 terminate 终止程序的执行。
6.13.3 标准异常
C++标准库定义了一组类,用于报告在标准库中的函数遇到的问题。
1. exception头文件定义了最常见的异常类,它的类名是exception。这个类只通知异常的产生,但不会提供更多的信息。
2. stdexcept头文件定义了几种常见的异常类。表中列出了头文件中定义的标准异常类。
| exception | 最常见的问题 |
| runtime_error | 运行时错误:仅在运行时才能检测到的问题 |
| range_error | 运行时错误:生成的结果超出了有意义的值域范围 |
| overflow_error | 运行时错误:计算上溢 |
| underflow_error | 运行时错误:计算下溢 |
| logic_error | 逻辑错误:可在运行前检测到的问题 |
| domain_error | 逻辑错误:参数的结果值不存在 |
| ivalid_argument | 逻辑错误:不合适的参数 |
| length_error | 逻辑错误:试图生成一个超出该类型最大长度的对象 |
| out_of_range | 逻辑错误:使用一个超出有效范围的值 |
6.14 使用预处理器进行调试
可用NDEBUG预处理变量实现有条件的调试代码:
int mian()
{
#ifndef NDEBUG
cerr << "starting main" << endl;
#endl
//...
开发完成后,可通过定义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 shor" << endl;
另一种调试技术是使用NDEBUG预处理变量以及asset(断言)预处理宏。assert宏是在cassert头文件中定义的。
assert(expr)
只要NDEBUG未定义,assert宏就求解条件表达式expr,如果结果为false,assert输出信息并且终止程序的执行。如果该表达式有一个非零值,则assert不做任何操作。在测试过程中,assert等效于检验数据是否总是具有预期的大小,一旦程序完成,并且定义了NDEBUG,assert语句就不做任何工作。assert仅用于检查确实不可能的条件。