表达式
- [x] 拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求
- [x] 如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象
- 这条规则有一个重要例外,当改变运算对象的子表达式本身就是另外一个子表达式的运算对象时该规则无效
- 例如,在表达式*++iter中,递增运算符改变iter的值,iter(已经改变)的值又是解引用运算符的运算对象,此时(或类似的情况下),求值的顺序不会成为问题,因为递增运算(即改变运算对象的子表达式)必须先求值,然后才轮到解引用运算,显然,这是一种很常见的用法,不会造成什么问题
- 在表达式求值之前,小整数类型的运算对象被提升成较大的整数类型,所有运算对象最终会转换成同一类型
- 当计算的结果超出该类型所能表示的范围时就会产生溢出
- 递增运算符和递减运算符
int i = 0,j;
j = ++i; //j = 1,i = 1:前置版本得到递增之后的值
j = i++; //j = 1,i = 2:后置版本得到递增之前的值
- 除非必须,否则不用递增递减运算符的后置版本
- 递增递减运算符的优先级高于解引用运算符(*)
- 解引用运算符(*)的优先级低于点运算符(.)
- 条件运算符(?:)
- [x] num > 60 ? "hi" : "faile"
- [x] 条件表达式的优先级非常低,因此当一条长表达式中嵌套了条件运算子表达式时,通常需要在它两端加上括号
-
size_of
运算符的结果部分的依赖于其 作用的类型
类型转换
- 自动执行的类型转换,无需程序猿的介入,有时甚至不需要程序猿去了解,就是
隐式转换
- [x] 如int + double
- [x] 常量整数值0或者字面值nullptr能转换成任意指针类型
- [x] 指向任意非常量的指针能转换成void*
- [x] 指向任意对象的指针能转换成const void *
- [x] 虽然有时不得不使用强制类型转啊混,但这种方法本质上是非常危险的
- [x] static_cast
- 任何具有明确定义的类型转换,只有不包含底层const,都可以使用static_cast
- double slope = static_cast<double>(j)/j; //进行强制类型转换以便执行浮点数除法
- [x] cosnt_cast
- const_cast只能改变运算对象的底层const
- const char * pc;
- char * p = const_cast<char *>(pc); //正确,但是通过p写值是未定义行为
- 对于将常量对象转换为非常量对象的行为,我们一般称其为`去掉const性质`,一旦我们去掉了某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了
- 如果对象本身不是一个常量,使用强制类型转换获得写权限是合法行为
- 如果对象是一个常量,再使用cosnt_cast执行写操作就会产生未定义的后果
- 只有const_cast能改变表达式的常量属性
- [x] 应当尽量避免强制类型转换
语句
简单语句
- C++语言中的大多数语句都以分号结束,末尾加上分号就变成了
表达式语句
- 空语句
- [x] 空语句中只含有一个单独的分号
- [x] 如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时会使用空语句
while(cin >> s && s != sought)
;
- [x] 使用空语句应该加上注释,从而令读这段代码的人指导该语句是有意省略的
条件语句
- 许多编译器和开发环境都提供一种辅助工具,它可以自动的缩进代码以匹配其语法结构,善用
-
switch
的case关键字和他对应的值一起被称为case标签
,case标签必须是常量整型表达式
- 可以省略
break
语句使得程序能够连续执行若干个case标签
switch (ch){
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
++n;
break;
}
//C++写法
switch (ch){
case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
++n;
break;
}
- 一般不要省略case分支最后的break语句,如果没写break语句,最好加一段注释说清楚程序的逻辑
-
default
标签
- [x] 如果没有任何要给标签能匹配上switch表达式的值,程序将执行紧跟在`default`标签后面的语句
switch (ch){
case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
++n;
break;
default:
....
break;
}
- 即使不准备在
default
标签下做任何工作,定义一个default标签也是有用的,其目的在于告诉程序的读者,我们已经考虑到了默认的情况,只是目前什么也没做
迭代语句
- 定义在while条件部分或者while循环体内的变量每次迭代都会经历从创建到销毁的过程
- 范围for语句
- [x] 不能通过范围for语句增加或删除vector对象(或其他容器)的元素
- [x] 在范围for语句中,预存了end()的值,一旦在序列中添加(删除)元素,end函数的值就可能变得无效
- do while语句应该在括号包围起来的条件后用一个分号表示语句结束
跳转语句
- [x] 负责终止离它最近的while,do while,for或switch语句,并从这些语句之后的第一条语句开始继续执行
- [x] 终止最近的循环中的当前迭代并立即开始下一次迭代
try语句块和异常处理
- 异常处理机制为程序中异常检测和异常处理两部分的写作提供支持,在C++语言中,异常处理包括:
- [x] throw表达式,异常检测部分使用throw表达式来表示它遇到了无法处理的问题,我们说用throw引发了异常
- [x] try语句块,异常处理部分使用try语句块处理异常,try语句块以关键字try开始,并以一个或多个catch子句结束,try语句块中代码抛出的异常通常会被某个catch子句处理,因为catch字句处理异常,所以它们也被称作`异常处理代码`
- [x] 一套`异常类`,用于在throw和相关的catch子句之间传递异常的具体信息
if(item.usbn() != item2.isbn())
{
throw runtime_error("Data must refer to name ISBN");
}
- [x] 类型`runtime_error`是标准库异常类型的一种
try{
program-statements
}catch(exception-declaration){
handle-statements
}catch(exception-declaration){
handle-statements
}