5. 语句
5.1 简单语句
-
C++中大多数语句以分号结束。
-
空语句:一个典型用法是用在while语句中。
使用空语句时,最好加上注释。 -
一条语句末尾多一个分号一般情况下无害。
但在循环语句中,可能带来一些意外结果。 -
复合语句,也被称作块。块不以分号作结束。
5.2 语句作用域
- 结构内部定义的变量,外部不可用。
5.3 条件语句
-
if语句:else只与最近的if匹配。
-
switch语句:
case标签必须是常量(整数、字符)。
break跳出当前switch语句。
case标签仅仅是入口,程序会继续执行接下来的语句,除非遇到break。
default标签:最好要有。如果没有内容,也必须要写一条空语句。 -
case语句内部若需要定义变量,应定义在块内。
每个case里的块里定义的变量,不能被其他case里的块里的语句使用。
5.4 迭代语句
-
while语句:经常用于不知道多少次循环时,比如输入。
-
传统for语句:
for (init-statement; condition; expression
传统for语句中,常见省略写法、以及逗号写法。
在init-statement中定义的变量,可以是多个,但类型必须相同。 -
范围for语句:
for (declaration : expression)
declaration定义的变量,可以使用auto
。
若需要对对象进行写操作,则应定义为引用类型,如auto&
。
expression表示的必须是一个序列、或一个对象
序列:花括号括起来的初始值列表。
对象:拥有能返回迭代器的begin和end成员的类型。 -
由3可知,不能通过范围for语句增加vector元素。
因为范围for中预存了end()的值,一旦删除或增加元素,end()函数将会无效。 -
do while语句:
记得while()后面有个分号。
变量既不能定义在do里,也不能定义在while里。
5.5 跳转语句
-
break:最近的:迭代语句、switch语句。
-
continue:最近的:迭代语句。
-
goto:无条件跳转,不建议使用。
goto语句、带标签的语句,必须在同一个函数内。goto label; label: //语句
5.6 try语句块和异常处理
-
异常是运行时的反常行为,其超出了函数正常的功能范围。
-
异常处理机制:异常检测 + 异常处理
throw表达式:异常检测部分使用throw表达式来表示它遇到了无法处理的问题。
try语句块:异常处理部分使用try语句块处理异常。
一套异常类:用于在throw表达式和相关的catch子句之间传递异常的具体信息。 -
throw表达式:
程序的异常检测部分使用throw表达式引发一个异常。
如果ISBN不一样就抛出一个异常,该异常是runtime_error类型的对象。
抛出异常将终止当前函数,并把控制权交给能处理异常的代码。
runtime_error是异常类型的一种,在stdexcept头文件中。
runtime_error必须初始化,即一个string对象或C风格字符串。if ( item1.isbn() != item2.isbn() ) throw runtime_error("Data must refer to same ISBN");
-
try语句块:
以关键字try开始,紧跟一个块,之后是一个或多个catch子句。
catch子句分为三个部分:关键字catch、声明、块。
选中了哪个子句,就执行对应的块。
catch一旦完成,就跳出整个try-catch内容。 -
程序本来要执行的任务出现在try语句块中,这是因为这段代码可能会抛出一个runtime_error类型的err。
what()是err的一个成员函数,返回值是C风格字符串。try{ item_total = item1 + item2; }catch(runtime_error err){ cout << err.what() << endl; }
-
寻找处理代码的过程与函数调用链刚好相反。
当异常抛出时,首先搜索抛出该异常的函数。
如果没有找到匹配的catch子句,终止该函数,并在调用该函数的函数中继续寻找。
如果仍没找到,则终止这个新的函数,继续搜索调用它的函数。
以此类推,直到找到适当类型的catch子句为止。
如果还是没找到,程序转到名为terminate的标准库函数。该函数的行为与系统有关,一般情况下,执行该函数将导致程序非正常退出。
对于那些没有任何try语句块定义的异常,也会按照类似方式处理。 -
异常中断了程序的正常流程。异常发生时,调用者请求的一部分计算可能已经完成了,另一部分未完成。
通常情况下,略过部分程序意味着某些对象处理到一半就戛然而止,从而导致对象处于无效或未完成的状态,或者资源未被释放。
那些在异常发生期间正确执行了“清理”工作的程序被称作异常安全的代码。
然而经验表明,编写异常安全的代码非常困难,也超出了本书范围。
通常我们只是简单的终止程序。但,有些对安全性有极高要求的特殊程序,就必须考虑这类异常。 -
标准异常:
C++标准库定义了一组类,用于报告标准函数库遇到的问题。
这些异常类被分别定义在了4个头文件中,可供用户编写程序使用。
exception
头文件:最通用的异常类exception,它只报告异常的发生,不提供任何额外的信息。
stdexcept
头文件:定义了几种常用的异常类。
new
头文件定义了bad_alloc
异常类型。
type_info
头文件定义了bad_cast
异常类型。异常类 说明 exception 最常见的问题(默认初始化) runtime_error 只有在运行时才能检测出的异常 range_error 运行时错误:结果超出值域 overflow_error 运行时错误:计算上溢 underflow_error 运行时错误:计算下溢 logic_error 程序逻辑错误 domain_error 逻辑错误:参数对应的结果值不存在 invalid_argument 逻辑错误:无效参数 length_error 逻辑错误:试图创建超出范围的对象 out_of_range 逻辑错误:使用一个超出范围的值 -
上述的异常类型中,除了exception、bad_alloc、bad_cast是默认初始化,其他异常类型都要在创建对象时提供初始值,且该初始值内含有错误相关信息。
-
异常类型值定义了一个名为what的成员函数,该函数没有任何参数,返回值是一个指向C风格字符串
const char*
,来提供关于异常的文本信息。 -
课本练习5.25:
int i1, i2; cin >> i1; while (cin >> i2) { try { if (i2 == 0) throw std::runtime_error("The second number can't be 0.\n"); if (i2 == 1) throw std::runtime_error("The second number can't be 1.\n"); } catch (std::runtime_error err) { cout << err.what() << "Please input the second number: " << endl; continue; } break; } cout << i1 / i2 << endl;