我一直认为,码代码时有一些强迫症是比较好的,这样写出来的代码干净整洁,至少看着就很舒服。在学习的过程中,我也见到、听到了不少在编程时要注意的小习惯,把它们整理一下,虽然不一定全面,但是我觉得还是可以参考的。
头文件的防卫式声明
在编写头文件时,使用这样的格式
1 |
|
这应该算是头文件的一种标准格式了。使用这种防卫式声明的好处是,别人在使用这个头文件时,不用考虑是否重复包含了头文件,或者包含头文件的顺序。如果头文件 a.h
没有这种防卫式声明,而 b.h
中包含了 a.h
,那么在程序中同时包含这两个头文件,在编译时就会出错。
头文件中不要使用 using
我最开始接触 C++ 的时候是高一,那时候每次写程序一上来就是固定的
1 |
|
但是并不知道每条语句的含义。直到大学看了一些书,才明白输入输出流、命名空间和主函数。但是这个习惯也一直保持到了现在……因为自己基本上都是使用标准的命名空间,所以写头文件时因为懒得写 std::string
就会直接在开头写上 using namespace std;
。
不过,后来在看书时发现,不要在头文件中使用 using 这句警告,因为如果在头文件中使用了 using,甚至直接引入标准命名空间的所有内容,在别人使用自己的命名空间的时候,可能会产生冲突,到时候真的是写程序一时爽,查BUG火葬场了……
所以说,偷懒真的不是什么好事情……
使用构造函数初始值
假设有一个 complex 类,下面这两个构造函数完成的功能是一样的,但是上面的代码效率更高。前者直接初始化数据成员,后者则先初始化再赋值。
1 | complex (double r = 0, double i = 0) // 默认实参 |
注意常量成员函数
我们仍然使用上面的 complex 类举例。
1 | class complex |
注意 complex 的两个成员函数 real() 和 imag(),它们并没有改变参数的值,因此他们在小括号后添加了 const,表示调用该函数的对象是一个常量。
如果不使用 const,显然 c1 在调用两个函数时是没有问题的。但是 c2 在调用这两个函数时,由于 c2 是常量,是不能改变的,而编译器会认为这两个函数有可能会改变 c2 的值,这是不允许的,此时就会出错。
因此,在编写程序时,要多注意这一点。这样做有利于提高函数的灵活性。
参数传递和返回尽量传递引用
C++在传递参数时,如果是传递参数的值,那么该参数有多大,就会传递多大的数据。比如,传递一个 double 类型,是4字节,就会传递 4 个字节。当数据量很大时,参数传递的量就会很大,会影响程序的效率。而传递引用则相当于传递指针。
当你在函数中不想修改参数的值时,可以令其为 const,这样编译器就不允许函数修改该参数。
同样,在函数返回时,如果能返回引用则尽量返回引用。但是不一定所有的函数都能够返回引用。例如,在complex body 外定义如下函数:
1 | inline complex& |
__doapl 函数返回了参数ths的引用。这样做是可以的。而另一种情况下
1 | int& plus(int a, int b) |
如果函数返回的是值而不是引用,程序会将返回值复制到临时变量区,从而返回这个值。而返回引用则会跳过这一环节。在上面的函数中,返回值 c 为局部变量,在函数调用结束后就会被释放,而返回 c 的引用相当于返回 c 的地址,之后程序再访问这个地址就会产生未定义的行为。
小结
虽然写了是萌新码代码的注意事项,看起来是给萌新看的,不过其实我应该也还算是萌新吧 ( ̄▽ ̄)" (虽然学编程的时间也不短了……)
这篇总结大部分都是来自侯捷老师的C++面向对象高级开发,最近看这个课件真的是受益匪浅,也很喜欢侯捷老师讲课的风格,推荐大家去看~