C++表达式和语句实用经验

文章内容整理自    刘光《C++程序员不可不知的101条实用经验》

1.运算符引发的混乱
①粗心导致的混乱,如将“==”写成了“=”,这种情况在if语句中能够编译通过
②优先级导致的混乱,如 cout << a ? “1” : “2”,程序本意是若a为真则输出“1”,否则输出“2”,但<<运算符的优先级比条件表达式的优先级高,应改正为 cout << (a ? “1”: “2”)
③结合性导致的混乱,如连续赋值a=b=c,因为“=”的结合性是从右往左,所以语义结构为a=(b=c)

2.尽量使用C++转化操作符
C++引入了4种转换操作符,分别是static_cast、const_cast、dynamic_cast、reinterpret_cast>
(1)static_cast<type_id >(expression )
①用于类层次结构中基类和子类之间指针或引用的转换
②进行上行转换(把子类的指针或引用转换成基类表示)是安全的
③把空指针转换成目标类型的空指针
④把任何类型的表达式转换成void类型
⑤static_cast可用于将一个void*类型的指针强制转换成其他的指针类型
小心陷阱:
①static_cast不能装换掉const,volatile或__unaligned属性
②进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的
③用于基本数据类型之间的转换,如把 int转换成char,把int转换成enum。这样转换的安全性也要开发人员来保证。
(2)dynamic_cast<type_id>(expression)
主要用于类层次间的上行和下行转换,还可以用于类之间的交叉转换。进行类层次间的上行转换功能和static_cast一样,因具有类型安全检查,下行转换比static_cast更安全。type_id必须是类的指针,类的引用或void*。
小心陷阱:
dynamic_cast要求派生类要有虚函数,否则编译不通过。而static_cast没有这个要求。
(3)reinterpret_cast<type_id>(expression)
type_id必须是一个指针,引用,算术类型,函数指针或者成员指针。如可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
因为能实现两个不相关类型的转换,所以比static_cast更危险,,应尽量避免使用。
(4)const_cast <type_id >(expression )
const_cast运算符用来修改类型的const或volatile属性。在使用过程中,除了const和volatile之外,type_id和experssion的类型是一样的。
常量指针/引用转换成非常量指针/引用,并仍然指向原来的对象;常量对象转换成非常量对象

3 .表 达式求值顺序不要想当然
表达式求值顺序不同于运算结合性和优先级,如i = ++i + 1;是一种未定义的行为
(1)函数参数的求值顺序
例如:
int a = 1;
int first_add()
{
        a += 1;
        return a;  
}
int second_add()
{
        a += 1;
        return a;  
}
int main()
{
        printf("fisr:%d,second:%d",first_add(),second_add());
        return 0;
}
这种情况下造成求值顺序不确定性使输出的结果可能是2,3,也可能是3,2
(2)操作数的求值顺序
a = p() + q() * r(),因为函数求值的不确定性,所以a的结果又多种可能,而运算符优先级的顺序只能保证q()和r()先相乘,但还是不能保证a只有一个结果。
(3)特殊求值顺序
若&&和||的惰性运算,前一个表达式的值能保证&&或||运算的结果,就不再继续后面的运算

4.switch_case的陷阱
请谨记:
(1)在使用switch_case结构时,在每个case标号分支语句最后,请务必添加一个break。如果在某些特殊情况下break不再需要,建议在此处添加注释进行说明
(2)除default标号外,每个case后面必须是一个 常量表达式,且不能存在两个case标号相同的情形。

5.a||b和a&&b的陷阱
请谨记:
(1)逻辑与&&和逻辑或||具有短路求值的特性
(2)明确区分逻辑与&&/逻辑或||和按位与&和按位或|的区别

6.“悬挂”else引起的问题
良好的编程风格可以避免悬挂else问题

7.标示语句结束的分号的思考
多一个分号和少一个分号有时能够躲过编译器的检查,但会和程序思想背道而驰,且很难查找出此类问题。

8.goto真的一无是处吗
goto语句会使代码难懂,运行速度变慢,但如果使用位置恰当也可以减少重复代码。,某些情况下运行速度更快且体积更小,比如说退出多层循环。这也是目前还留下goto语句的原因。

9.条件操作符和逗号操作符
条件运算符和逗号运算符时C++为数不多的规定求值顺序的操作符,同时也是仅有的两个多目运算符

10.同魔鬼数字说再见
魔鬼数字也被称为幻数,指的是那些上下文里出现的字面常量,可以是数字也可以是字符串。实际编程中应使用const定义这些字面值常量。

11.关于循环语句的讨论
请谨记:
(1)不可以在for循环中修改循环变量,防止for循环失去控制
(2)建议for循环的循环控制变量的取值采用“半开半闭区间”写法,因为这种写法更加直观。
(3)do...while除了作为循环使用外,最重要的是还能用于宏定义,能够提高代码的健壮性
(4)为了提高循环的效率,应将循环次数小的循环放到外层,循环次数大的循环放到内层









猜你喜欢

转载自blog.csdn.net/sinat_39061823/article/details/80569244