本篇对C++世界的关键之处作以补充,便于初学者对C++有一个直观的了解,可以作为第三篇的参考材料。
每个C++ 程序通常分为两个文件。一个文件用于保存程序的声明(declaration),称为头文件。另一个文件用于保存程序的实现(implementation),称为定义(definition)文件。C++程序的头文件以“.h”为后缀,C++程序的定义文件通常以“.cpp”为后缀(也有一些系统以“.cc”或“.cxx”为后缀)。头文件主要包括一些预编译命令以及函数、类结构的声明等。定义文件则包含了对一些头文件的引用,还有程序的实现体(包括数据和代码)。
头文件(header)的作用大致有两点:(1)通过头文件来调用库功能。某些情况下源代码不向用户公布,只要提供编译后的二进制库文件和相应的头文件即可,用户按照头文件中对接口的声明来使用库,编译器会从库中提取相应的代码(二进制)。(2)头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。
C++中的运算符有数十个,清楚它们的优先级与结合律对编写逻辑复杂的代码至关重要(当然,过于复杂的表达式逻辑,强烈建议适当地使用括号,以增强代码的可读性)。下表简要说明了各运算符的优先级与结合律。
| 优先级 |
运算符 |
结合律 |
从
高
到
低
排
列 |
( ) [ ] -> . |
从左至右 |
! ~ ++ — (类型) sizeof
+ – * & |
从右至左 |
| * / % |
从左至右 |
| + - |
从左至右 |
| << >> |
从左至右 |
| < <= > >= |
从左至右 |
| == != |
从左至右 |
| & |
从左至右 |
| ^ |
从左至右 |
| | |
从左至右 |
| && |
从左至右 |
| || |
从右至左 |
| ?: |
从右至左 |
= += -= *= /= %= &= ^=
|= <<= >>= |
从左至右 |
if语句是C++中最常用也最简单的语句,需要注意的有:(1)else子句是可选的;(2)多级if的排版要注意美观以防止发生错误;(3)在不过于冗余的情况下尽量多地使用花括号,以保证代码结构严谨;(4)if的条件是与零比较,非零的值都表示条件成立。
for语句在越专业的C++代码中出现的频率就越高,因为它极为灵活。对于初学者最需要注意的就是,for的括号中声明的变量在for语句之外是不可用的。比如“for(int i = 1; i <= 10; ++ i) { cout << i << endl; }”将打印出1~10的值,此后i就“消失”了,再写比如“cout << i << endl;”就是错误的了。
上一段的论述是片面的,下面考虑真正的带有“域”的情况。C++中一个域(scope)就是由花括号包围起来的一个相对独立的代码区间(当然也包含省略了花括号的单条语句)。变量作用范围对应着相应的域,即变量作用域,其核心概括起来有三点:(1)同一域内声明的变量对于声明语句之后的语句可用;(2)上级域中声明的变量对下级域(子域)可用,而反之则不可用(作用域终止);(3)下级域(子域)内声明的变量会覆盖上级域中的同名变量,但域终止后不会对以后有影响。
常量的定义与声明是在一起的(或者说声明的同时就初始化),使用像“const float PI = 3.14;”的格式声明常量。不要使用C语言中遗留下来的#define预编译命令来定义所谓的常量,因为它只是简单地进行格式替换,并不包含语法信息,编译器也不会报告潜在的语义错误。同样,简短的方法应使用inline内联定义,而不是#define。
C++函数参数可以按值传递(pass by value),也可以按引用传递(pass by reference)。引用(reference)是C++中很重要的一个概念,与之紧密相关的指针则是C++深入学习的重头戏。我们在这里简单地看一下引用的一个应用:“void swap(int &a, int &b) { int t = a; a = b; b = t; }”。这个swap()函数用来交换两个int的值,可以这样使用:“int x = 1, y = 2; swap(x, y);”。上面的语句执行完后,x的值变为2而y的值变为1。而如果把swap()声明部分的“&”符号去掉,则对传入的值并没有影响。
回顾我们最开始的“Hello World”程序(注:在这个版本的教程中这个入门示例从第一篇砍掉了,我会在本教程的结束篇把最初版本的关于环境配置的图片打包发布,其中就包含了这个程序):
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}
这段代码将打印出一行“Hello World!”字样。我们称“”Hello World!””为字符串字面量(string literal)。字符串,顾名思义,就是一串字符,用来显示一些数字之外的有意义的信息。从C到C++,字符串一直没有被很好地支持:C中没有原生的字符串,使用字符(char)数组来表示“串”;C++中有了STL实现的string,大多数情况下可以当做原生的类型使用,但与C字符数组等的关系又很复杂,其间涉及到非常关键的指针的内容。所以,关于字符串,真正在基础范围内的东西很少,几乎也只有一个字面量而已;如果把字符串“基础”化了,必然会使读者入了歧途,所以希望读者可以自己参考相关的权威书籍(本篇末尾会推荐)。
那么,如果不展开去讲字符串,回顾这个“Hello World”干嘛呢?其实是让你真正看看C++世界与现实世界边缘的一些东西。考虑下面的代码:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
cout << "argc = " << argc << endl;
for (int i = 0; i < argc; ++ i)
cout << "argv[" << i << "] = " << argv[i] << endl;
return 0;
}
亲自从命令行运行上面的代码。比如存盘为cpptut6.cpp,编译后为cpptut6.exe,在命令行下输入“cpptut6 blabla hahaha”,观察输出结果。更换命令行参数多试几次,体会一下主函数main()的这种声明格式的作用。
好了,这篇差不多也应该结束了。有朋友说教程太过“简”,根本没学明白。那么我就在这里推荐一些书籍留作后续的学习。在看这些书籍之前,保证你看过本教程两遍以上(我指有不同体验的两遍),才有提升的效果。注意,第六篇不是最后一篇,还有第七遍,不过那将是关于C++的一些代码例子,让你更加深入熟悉C++的,所以本篇是最后一篇说明性的文字了。嗯,不啰嗦了,列出推荐书籍如下:
- The C++ Programming Language —— C++发明者编写的书籍
- Professional C++ —— 精通C++的首选
- The C++ Standard Library —— 关于库的使用(我在第四篇发过了)
- C++ Primer —— 很厚,如果以上三本书实在不愿意看,看Primer吧
(本篇完;做人要厚道,转载请注明出处)