第二章:进入 C++
内容包括:
- C++ 程序的一般格式;
#include
指令;main()
函数;- 使用
cout
对象进行输出; - 在C++程序中加入注释;
- 何时以及如何使用
endl
; - 声明和使用变量;
- 使用
cin
对象进行输入; - 定义和使用简单函数。
2.1 进入 C++
C++对大小写敏感,对拼写也是敏感的,所以不能使用如COUT
和Kout
等单词
*cpp
*是一种表示 C++ 程序的方式
1 | // myfirst.cpp -- display a message |
2.1.1 main() 函数
去掉修饰后,程序 2.1 的基本结构会是这样
1 | int main() |
这几行表明有一个 main 函数,并描述了该函数的行为。
这几行代码构成了函数定义(function definition)。
该定义有两部分组成:
- 第一行
int main()
叫函数头。 - 花括号({和})中包括的部分叫做函数体。
函数体是指出函数因该做什么的计算机指令、在C++中,每一条完整的指令都被称为语句,语句以;
结尾。
main()
中最后一条语句为结束语句(return statements),它用来结束函数。
语句和分号
语句是要执行的操作,C++ 和 C 不像 Python 或 Pascal 一样使用回车做语句的结尾,终止符是一个分号,它是语句结束的标记,
是语句的组成部分,而不是语句之间的标记。结论是在 C++ 中不能省略分号。
1.作为接口的函数头
下面的函数头表明`main()`函数可以调用他的函数返回一个整数值,
且不从调用他的函数那里获得任何东西:
1 | int main() |
有很多现有的程序使用经典的C语言函数头:
1 | main() |
在C语言中,省略返回类型则默认为 int ,当然可以使用下列变体:
1 | int main(void) |
括号中的`void`指出函数不接受任何的参数,在C++中,让括号空着等效于在括号中使用`void`
当然也可以使用下面的函数头,并省略返回语句:
1 | void main() |
如果不在`main()`函数后增加返回语句,编译器将默认为:
1 | return 0; |
**这条隐式语句只适用于*`main()`函数***
2. 为什么 main()
不能使用其他名称
是因为必须这么做,通常C++程序必须包含一个`main()`函数(不是`Main()`、`MAIN()`或`mane()`)
存在一些列外情况,比如在Windows编程中可以编写一个动态链接库(DLL)模块,
这是其他Windows程序可以使用的代码。由于DLL不是独立的程序,所以不需要`main()`,
亦或是一些框架程序或机器人中的控制芯片。
2.1.2 C++ 注释
C++注释以`//`打头,使用时编译器会自动跳过,它可以位于新的一行,也可以和代码在同一行。
C++也能识别C语言注释 C 注释包括在 /*
和 */
之间,由于它以*/
结尾,所以可以跨越多行。
2.1.3 C++预处理器和 iostream 文件
如果要是程序能够进行输入和输出,则会使用如下代码:
1 |
|
当然可以使用其他代码替换掉第二行,第一行的`#include <iostream>`编译指令使预处理器将`iostream`文件的添加到程序中。
这是一种典型的预处理器做法:在源代码被编译之前,替换或添加文本。
这提出了一个问题,为什么要将`iostream`文件的内容添加到程序中呢?
答案涉及到程序与外部的通信。iostream
中的io
是指输入(进入程序的信息)和输出(从程序中发出的信息)。C++的输入和输出方案涉及iostream
文件中的多个定义。为了使用cout
来显示消息,第一个程序需要这些定义。为了使用cout
来显示消息,第一个程序需要这些定义。
#include编译指令导致iostream
文件的内容随源代码的内容一起被发送给编译器。实际上,iostream
文件的内容将会取代程序中的代码行
1 |
原始文件没有被修改,而是将源代码文件和iostream
组成一个复合文件,编译的下一阶段将要使用到该文件。
注意:使用cin
和cout
进行输入和输出的程序时必须包含文件iostream
。
2.1.4 头文件名
想`iostream`这样的文件叫做包含文件(include file)——由于他们被包含在其他文件中;也叫做头文件(head file)——
由于它们是被包含在文件的起始处。C++编译器自带了许多头文件,每个头文件都支持一组特定的工具。C语言的传统是,头文件
使用扩展名 h,将其作为一种通用名称标识文件类型的基本方式
列如,头文件math.h
支持c语言的数学运算函数,但是C++的用法变了。
现在,C++对老式的C语言扩展头.h
做了保留,而C++则没有扩展名。
有些C头文件被转换成C++的头文件,并在文件名的最前面加上c
来表明他原来是C的头文件,如cmath
总而言之
头文件类型 | 约定 | 示例 | 说明 |
---|---|---|---|
C++旧式风格 | 以.h 结尾 |
iostream | C++ |
C旧式风格 | 以.h 结尾 |
math.h | C、C++ |
C++新式风格 | 没有扩展名 | iostream | C++(使用 namespace std) |
转换后的C | 加上前缀C,没有扩展名 | cmath | C++(可以使用不是C的特性) |
由于C使用不同的扩展名表示不同的文件类型,因此会出现一些不同寻常的扩展名(如`.hpp`和`.hxx`)来表示C++的的头文件是有道理的。
2.1.5 名称空间
如果使用`iostream`,而不是`iostream.h`,则使用如下指令
1 | using namespace std; |
不要着急它是干嘛用的,在以后再了解
`namespace`是C++的特性,比如有两个封装好的代码`Microflop`和`Piscine`要想同时使用时该怎么办呢,
就不能使用using namespace std
了,这时可以使用
1 | Microflop::wanda("Go dancing?") //use Microflop namespace stdPiscine::wanda("A fish named Tom") //use Piscine namespace std |
这就可以区分两个wanda()
的不同之处了
2.1.6 使用cout进行C++输出
现在来看看C++是如何输出信息的,在`myfirst.cpp`中是这样的
1 | cout << "Come up and C++ me some time"; |
双引号括起来的是字符串,也就是要打印的消息。<<
把这个字符串发送给cout
而cout
是一个预定义的对象,它知道如何显示字符
1.控制符endl
1 | cout << endl; |
现在来看看这个例子,endl表达一个重要的概念:重起一行()(输出一段后默认不换行)
在输入流中加入它会使光标移至下一行。诸如endl等对cout有意义的字符被称为***控制符(manipulator)***和cout一样,endl实在iostream中定义的,且位于命名空间std中
2.换行符
C++还提供了一种旧式用法:\n
它被视为一个字符换行符
换行符是一种被称为”转义序列“的按键组合
2.1.7 C++源码格式化
在C++中,;
代表了语句的结束,通常,在能使用回车的地方也能使用空格,反之亦然
但是,不能把空格、制表符或回车放在元素(如名称),也不能把回车放在字符串中间
如下就是一个错误例子:
1 | int ma in()return 0;cout << "Behold the Beans of Beauty!"; |
1.源代码的标记和空白
一行代码中不可分割的一部分叫做标记(token)
通常必须用空格、制表符或回车将标记分开。有些字符如,
或()
是不需要用空白分开的标记
如下举例说明了何种情况需要分开,什么情况下可以省略
1 | return0; //INVALLD, must be return 0;return(0); //VALLD, white space omittedreturn (0); //VALLD, white space useintmain(); //INVALLD, white space omittedint main() //VALLD, white space omitted in ()int main () //VALLD, white space in () |
2. C++源代码风格
- 每条语句个占一行
- 每个函数都有一个开始花括号和一个结束花括号,两个花括号个占一行
- 函数中的语句都要相对于花括号进行缩进
- 与函数名称相关的花括号周围没有空白
前三条规则用来保证代码清晰可读,第四条用来帮助区分函数和一些也使用圆括号的C++内置结构(如循环)
2.2 C++语句
C++程序是一组函数,而每个函数又是有一组语句组成的
1 |
空白部分将声明语句和其他语句分开,这是C的常用用法,但在C++中并不常见
2.2.1 申明语句和变量
例如,在2.2的程序中包含了这样一条声明语句
1 | int carrots; |
这条语句提供了两个信息:需要的内存,以及该内存单元的名称,这条语句指出程序需要足够的储存来储存一个整数
,在C++中int表示整数——没有小数部分的数字。
C++的int类型可以为正,也可为负,但大小取决于实现
完成的第二项任务时给储存单元指定名称。在这里,该声明语句指出,此后程序使用名称carrots
来标识储存在该内存单元的值。carrot
被称为变量,因为它的值可以修改,在C++中,所有的变量必须声明(尽可能在首次使用时声明)
2.2.2 赋值语句
赋值语句将值赋给储存单元,例如,下列语句将25赋给表示变量carrots的内存单元
1 | carrots = 0; |
符号=
叫做赋值运算符。C++和C语言都有一个特性——可以使用连续赋值运算符。例如下面的例子:
1 | int steinway;int baldwin;yamaha = baldwin = steinway = 88 |
赋值是从右向左进行的
2.2.3 cout的新花样
cout可用于数字和字符串。但是别忘了,整数25和字符串“25"有天壤之别。
程序没有打印carrots
,而是打印存储在carrots
中的整数值。实际上,这两个操作和二为一了。首先,cout将carrots替换为其当前值25,然后把值转换为合适的输出字符。
2.3 其他C++语句
再来看几个C++语句的例子
1 | // getinfo.cpp -- input and output |
第一条cin语句在输入输入数字按下enter建时读取输入,第二个cin语句让程序暂停,直到摁下enter建。
2.3.1 使用cin
上面的输出表明,从键盘中输入的值(12)会被最终赋值给carrots。下面就是执行这项功能的语句:
1 | cin >> carrots; |
从这条语句可知,信息从cin流向carrots
2.3.2 使用cout进行拼接
getinfo.cpp的一项新特性是将四条语句合并成一条。iostream定义了<<运算,以便可以像下面这样合并(拼接)输出
1 | cout << "a" << "b" << "c" << "d"; |
也可以这样写
1 | cout << "a"; |
当然也可以这样
1 | cout << "a" |
2.3.4 类简介
类是用户定义的一种数据类型。要定义类需要描述它能够表示什么东西和可对数据进行哪些操作。
类之于对象就像类型之于变量。
接下来更具体一些,前文中讲过下面的变量声明
1 | int carrots; |
这句代码将创建一个类型为int的变量。也就是说carrots可以储存整数可以按特定的方法使用,比如说加或减。现在来看cout,它是一个ostream类对象。ostream类定义(iostream文件的另一个成员)