1. 简单语句
C++语言中的大多数语句都以分号结束,表达式语句的作用是执行表达式并丢弃掉求值结果。
最简单的语句是空语句,空语句中只含有一个单独的分号。
空语句一般用于语法上需要一条语句但是逻辑上不需要的地方。
使用空语句时应该加上注释,从而令阅读代码的读者知道该语句是有意省略的。
复合语句是指用花括号括起来的(可能是空语句)语句和声明的序列,复合语句也被称为块。
一个块就是一个作用域,在块中引入的名字只能在块内部以及子块中访问。
复合语句使用在语法上需要一条语句,但是逻辑上需要多条语句的地方。
块不以分号作为结束,以左花括号({)为开始标识符,以右花括号(})为结束标识符。
2. 语句作用域
在if、switch、while和for语句的控制结构内定义变量,一旦语句结束,变量就超出其作用范围。
while(int i = get_num()) //i是控制变量,每次迭代时会创建并初始化
cout << i << endl;
i = 0; //错误,语句结束,变量超出其作用范围
由于控制结构定义的对象的值马上要被结构本身使用,所以控制变量必须初始化。
3. 条件语句
1. if语句
if语句的作用:判断一个指定的条件是否为真,根据判断结果决定是否执行另外一个语句。
if语句有两种形式:一种含有else分支,另一种没含有else分支。
if(condition)
statement
else if(condition2) //else if 可以无限设置
statement
else //else语句无需设置condition
statement
condition是一个表达式或一个初始化了的变量声明,不管是表达式还是变量,其类型必须能转换成布尔类型。
允许在if语句或else语句中嵌套if语句,将子if语句放在相对应的块中。
当一个if语句嵌套在另一个if语句内部时,if分支可能会多于else分支,这样的情况可能会出现混淆else是与哪个if匹配的问题,这个问题被称为悬垂else。
C++语言规定,else与离它最近的尚未匹配的if匹配,从而消除了程序的二义性。
使用花括号控制执行路径。
if(condition)
{
if(condition2)
statement
}
else
{
statement
}
2. switch语句
switch语句提供了一条便利的途径使得我们能够在若干固定选项中做出选择。
switch(condition){ //switch先对括号内的表达式求值,值转换成整数类型
case'a': //与每个case标签中的值比较
statement;
break;
case'b':
statement;
break;
case'c':
statement;
break;
}
break语句的作用是中断当前的控制流,将控制权转移到switch语句外面去。
case关键字和它对应的值一起被称为case标签,case标签必须是整型常量表达式。
任何两个case标签的值不能相同,否则就会引发错误。
在下一个case标签之前应该有一条break语句,避免匹配成功却没有中断过程的情况发生。
一个case标签只能对应一个值。
如果没有任何一个case标签能匹配上switch表达式的值,程序会自动执行default标签。
switch(condition){
case'a':
statement;
break;
default:
statement1;
break;
}
即使不准备再default标签下做任何工作,定义一个default标签也能告诉读者,我们已经考虑到了默认情况。
switch的执行流程有可能会跨过某些case标签,这样可能会引发一些未定义的行为。
不允许在case中初始化变量,但允许在case中声明变量。(程序在编译过程就已经知道该声明变量)
如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有case标签都在变量的作用域之外。
4. 迭代语句
while和for语句在执行循环体之前检查条件,do while语句先执行循环体,然后再检查条件。
1.while语句
只要条件为真,while语句就重复地执行循环体。
while(condition)
statement
定义在while条件部分或者while循环体内的变量每次迭代都经历从创建到销毁的过程。
当不确定到底要迭代多少次时或想在循环结束后访问循环控制变量,使用while循环比较合适。
2.传统的for语句
for语句的格式是:
for(init-statement;condition;expression)
statement
//init-statement负责初始化一个值
//condition作为循环控制的条件
//expression用来修改init-statement初始化的变量
for语句头中定义的对象只在for循环体内可见。
init-statement可以定义多个对象,但是init-statement只能有一个声明语句,因此,所有变量的基础类型必须相同。
for语句头能省略掉init-statement、condition 和 expression 中的任何一个(或者全部)。
3.范围for语句
范围for语句可以遍历容器或其他序列的所有元素,语句格式如下:
for(declaration:expression)
statement
//expression表示的必须是一个序列,例如数组、vector或string类型的对象
//declaration定义一个变量,使用auto类型。
expression所表示的类型拥有能返回迭代器的begin和end成员的特点。
如果需要对序列中的元素执行修改操作,循环变量必须声明成引用类型。
每次迭代都会重新定义循环控制变量,并将其初始化成序列中的下一个值。
在范围for语句中,预留了end()的值,因此,不能在序列中添加或删除元素。
4.do while语句
do while语句先执行循环体后检查条件,不管条件的值如何,我们都至少执行一次循环。
do
statement
while(condition); //条件后面用一个分号表示语句结束
求condition的值之前会先执行一次statement,condition不能为空;因此condition使用的变量必须定义在循环体之外。
5. 跳转语句
1.break语句
break语句负责终止离它最近的while、do while、for或switch语句,并从这些语句开头开始执行。
2.continue语句
continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。
3.goto语句
goto语句的作用是从goto语句无条件跳转到同一函数内的另一条语句。
建议不要再程序中使用goto语句,因为它使得程序即难理解又难修改。
goto label; //label是一条语句的标示符
statement
label: //注意:不要省略了冒号
从goto label跳转到下一个label处开始,statement被省略。
label标示符可以和程序中其他实体的标示符使用同一个名字而不会相互干扰。
向后跳过一个已经执行的定义是合法的。
begin:
statement
goto begin;
6. try语句块和异常处理
异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。
异常处理机制为程序中异常检测和异常处理这两部分的协助提供支持。
异常处理包括:
throw表达式:异常检测使用throw表达式来表示其遇到了无法处理的问题。
try语句块:异常处理部分使用try语句块处理异常,块以关键字try开始,并以一个或多个catch子句结束;catch子句被称作异常处理代码。
1.throw表达式
throw表达式引发一个异常;throw表达式包含关键字throw和一个表达式,其中表达式的类型是抛出的异常类型,结尾使用分号作为结束标识。
throw runtime_error("condition");
//该异常是类型runtime_error的对象,抛出异常并终止函数,将控制权移交给能处理异常的catch语句
类型runtime_error是标准库异常类型的一种,定义在stdexcept头文件中。
runtime_error类型必须初始化,初始化一个string对象或者字符串,提供一些关于异常的辅助信息
2.try语句块
try语句块的通用语法形式:
try{
program-statement //组成程序的正常逻辑
}
catch(exception-declaration){ //exception-declaration是异常声明
handler-statement //解决方案代码
}
catch(exception-declaration){
handler-statement
}
try语句块内声明的变量在块外部无法访问,特别是在catch子句内也无法访问。
当一个异常被抛出时,系统会沿着程序执行路径逐层回退,直到找到适当类型的catch子句为止。
如果最终没能找到匹配的catch子句,程序会转到名为terminate的标准库函数。
terminate函数的行为与系统有关,一般执行该函数将导致程序非正常退出。
如果程序没有try语句块且发生了异常,系统会调用terminate函数并终止当前程序的执行。
3.标准异常
C++标准库中定义了一些异常类用于报告标准库函数遇到的问题。
1、exception头文件定义了最通用的异常类exception。它只报告异常情况的发生。
2、 stdexcept头文件定义了集中常用的异常类。
3、new头文件定义了bad_alloc异常类型。
4、type_info头文件定义了bad_cast异常类型。
exception | 最常见的问题 |
runtime_error | 只有在运行时才能检测出的问题 |
range_error | 运行时错误:结果超出值域范围 |
overflow_error | 运行时错误:计算上溢 |
underflow_error | 运行时错误:计算下溢 |
Iogic_error | 程序逻辑错误 |
domain_error | 逻辑错误:参数对应的结果值不存在 |
invalid_argument | 逻辑错误:无效参数 |
length_error | 逻辑错误:试图创建一个超出类型最大长度的对象 |
out_of_range | 逻辑错误:使用一个超出有效范围的值 |
我们只能以默认初始化的方式初始化exception、bad_alloc和bad_cast对象,不允许为这些对象提供初始值。
其他异常类型应该使用string对象或字符串初始化,但是不允许使用默认初始化方式。