前言
个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系。
一直以来都很想深入学习一下C++,将其作为自己的主力开发语言。现在为了完成自己这一直以来的心愿,准备认真学习《C++ Primer Plus》。
为了提高学习效率,在学习的过程中将通过发布学习笔记的方式,持续记录自己学习C++的过程。
本篇前言
学习计算机语言,应从程序的基本结构开始学起。这就犹如建房屋,首先需要打地基、搭框架。
一、进入C++
首先使用C++工具cout
生成字符输出,写一个显示消息的简单C++程序。通过//
可以对代码提供注释,编译器会忽略它们。
C++对大小写敏感。
程序清单2.1 myfirst.cpp
//myfirst.cpp -- 显示消息
#include <iostream> //预处理器指令
int main() //函数头
{ //函数体开始
using namespace std; //使定义可见
cout<<"一起来学习C++吧。"; //消息
cout<<endl; //开始新的一行
cout<<"我想你不会拒绝的!"<<endl; //更多的输出
return 0; //终止main()
} //函数体结束
通过之前《CMake学习笔记(一)》文章,可以得到以上代码的运行结果:
一起来学习C++吧。
我想你不会拒绝的!
1、mai()函数
将程序清单2.1进行简化,就得到如下代码结构:
在C++中,每条完整的指令都称为语句,所有语句都以分号结束。
main()
中最后一条语句叫作返回语句(return statement),它的作用是结束当前函数。编译器到达mian()
函数末尾没有遇到返回语句,则默认返回语句为return 0;
(默认返回语句仅适用mian()
函数)。
通常情况下在运行C++程序时,main()
函数将被启动代码调用,而启动代码是由编译器添加都程序中的,是程序和操作系统之间的桥梁。如果未定义main()
函数,程序将不完整。
2、C++注释
C++有两种注释:
- 双斜杠(
//
)打头,注释一行。注释可以单独一行,也可以和代码同行。 - 在符号
/*
和*/
之间,注释可以跨行。
注释不仅有助于他人理解这些代码,更有助于开发者自己理解(有开发经验的小伙伴对这一点一定有很深刻的认识)。
3、C++预处理器和iostream文件
程序清单2.1 使用了#include
编译指令:
#include <iostream> //预处理器指令
该编译器指令导致预处理器将iostream文件的内容添加到程序中。这是一种典型的预处理器操作:在源代码被编译之前,替换或添加文本。
4、头文件名
头文件(被包含在文件起始处)也称包含文件,因为它们被包含在其他文件中。C++编译器自带很多头文件,每个头文件都提供了一组特定的工具。
头文件命名约定:
头文件类型 | 约定 | 示例 | 说明 |
---|---|---|---|
C++旧式风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
C旧式风格 | 以.h结尾 | math.h | C、C++程序可以使用 |
C++新式风格 | 没有扩展名 | iostream | C++程序可以使用,使用namespace std |
转换后的C | 加上前缀c,没有扩展名 | cmath | C++程序可以使用,可以使用不是C的特性,如namespace std |
5、名称空间
名称空间支持是一项C++特性,旨在让编写大型程序以及将多个厂商现有的代码组合起来的程序时更容易,同时它也有助于组织程序。
为了解决名称空间引入后的代码转换问题,using
编译指令应运而生。
通过以下代码可以将iostream
中的std
命名空间中的所有名称引入当前程序代码文件中:
using namespace std;
如果不引入名称空间,则需要将名称空间用两个:
与工具名相连,来使用工具:
std::cout<<"Hello World."<<std::endl;
6、使用cout
进行C++输出
程序清单2.1 中使用了cout
进行C++输出:
cout<<"一起来学习C++吧。"; //消息
cout的对象属性包括一个插入运算符(<<
),它可以将其右侧的信息插入到流中。
运算符重载:插入运算符(<<)与按位左移运算符(<<)看上一去一样,这就是运算符重载。通过重载,同一个运算符可以拥有不同的含义。编译器通过上下文来确定运算符的含义。
(1)控制符endl
endl
是一个特殊的C++符号,表示一个重要的概念:重起一行。诸如endl
等对于cout
来说有特殊含义的特殊符号被称为控制符(manipulator)。
和cout
一样,endl
也在头文件iostream
中定义的,切同位于名称空间std
中。
(2)换行符
以下两行代码都有换行的作用:
cout<<"\n";
cout<<endl;
但endl
可以确保程序继续运行前刷新输出,而\n
不能提供这样的保证。
换行符是一种被称为“转义序列”的按键组合。
7、C++源代码的格式化
在C++中,分号标示了语句的结尾,不能把空格、制表符或回车放在元素(比如名称)中间。
二、C++语句
C++程序是一组函数,而每个函数又是一组语句。程序清单2.2提供了两种新的语句,分别是声明语句创建变量,赋值语句给变量提供值。
程序清单2.2 carrots.cpp
// carrots.cpp -- 食品加工项目
//使用并显示一个变量
#include <iostream>
int main()
{
using namespace std;
int carrots; //声明一个整型变量
carrots = 25; //给变量赋值
cout << "我有";
cout << carrots;//显示变量的值
cout << "个胡萝卜。";
cout << endl;
carrots = carrots - 1;//修改变量的值
cout << "现在我有" << carrots << "个胡萝卜。" << endl;
return 0;
}
1、声明语句和变量
在程序清单2.2中包含了这样一条声明语句:
int carrots;
这条语句提供了两项信息:需要的内存以及该内存单元的名称。具体地说,这条语句指出程序需要足够的空间来存储一个整数,在C++中用int表示整数。编译器负责分配和标记内存的细节。
该声明语句指出,此后程序将使用名称carrots来标识存储在该内存单元中的值。carrots被称为变量,因为它的值可以修改。在C++中,所有变量都必须在首次使用前声明它。
在C++中,所有变量都必须声明。
2、赋值语句
在程序清单2.2中包含了下面这条赋值语句,表示将整数25赋值给变量carrots表示的内存单元:
carrot = 25;
符号=
叫作赋值运算符。
3、cout的新花样
程序清单2.2中使用cout
来打印变量,该变量是一个整数:
cout << carrots;
cout
使用C++面向对象的特性,实现能够自动识别类型。
三、其他C++语句
程序清单2.3在程序清单2.2的基础上进行了扩展,使用cin
在程序运行时输入一个值:
// getinfo -- 输入和输出
#include <iostream>
int main()
{
using namespace std;
int carrots;
cout << "你有几个胡萝卜?" << endl;
cin >> carrots; // C++输入
cout << "这儿还有两个。";
carrots = carrots + 2;
//在下一行连接输出
cout << "现在你有" << carrots << "个胡萝卜。" << endl;
return 0;
}
该程序的运行结果:
你有几个胡萝卜?
100
这儿还有两个。现在你有102个胡萝卜。
该程序包含两项特性:用cin
来读取键盘输入以及通过cout
进行输出拼接。
(1)使用cin
通过使用cin
可以将键盘输入的值赋值给变量。
同cout
一样,cin
也是一个智能对象。可以将键盘输入的一系列字符转换为接收变量能够接受的形式。
(2)使用cout进行拼接
iostream文件定义了<<
运算符,以便可以像下面这样拼接输出:
cout << "现在你有" << carrots << "个胡萝卜。" << endl;
(3)类简介
类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息和可对数据执行那些操作。类之于对象就像类型之于变量。也就是说,类定义描述的是数据格式及其用法,而对象则是根据数据格式规范创建的实体。换句话说,如果说类就好比所有著名演员,则对象就好比某个著名的演员。
cout
是ostream
类对象。
四、函数
C++函数分两种:有返回值和没有返回值的。
1、使用有返回值的函数
有返回值的函数生成一个值,而这个值可赋给变量或在其他表达式中使用。
在标准C/C++库中有一个名为sqrt()
的函数,它返回平方根。
x = sqrt(9); // 返回值3并赋值给x
以上语句中的表达式sqrt(9)
将调用sqrt()
函数,表达式sqrt(9)
被称为函数调用,被调用的函数叫作被调用函数(called function),包含函数调用的函数叫作调用函数(calling function)。
我们将以上语句稍微拓展完善一下:
//引入了一个新的cmath头文件和double类型,这些都先忽略
#include <cmath> // 或者 math.h
int main()
{
double x = sqrt(9); // 返回值3并赋值给x
}
以上程序中main()
就是调用函数,sqrt()
就是被调用函数。圆括号中的值9
就是函数sqrt()
的参数,函数sqrt()
的返回值就是赋值给变量x
的值。
在使用函数之前,C++编译器必须知道函数的参数类型和返回值类型。C++提供这种信息的方式就是使用函数原型语句(通常做法是把原型放置到main()
函数定义的前面)。函数原型之于函数就像比变量声明之于变量——指出涉及的类型。sqrt()
函数原型就像这样:
double sqrt (double x);
在程序中使用sqrt()
函数时,有两种方法提供原型:
- 在源代码文件中输入函数原型;
- 包含头文件cmath(老系统为math.h),其中定义了原型。
函数原型和函数定义的区别: 原型只描述函数接口(发送给函数的信息和返回的信息),而定义包含了函数的代码。C和C++将库函数的这两项特性分开了,库文件包含函数的编译代码,头文件则包含原型。
C++库函数存储在库文件中。编译器编译程序时,它必须在库文件搜索到使用的函数。至于搜索哪些库文件,将因编译器而异。
2、函数变体
- 有些函数需要多项信息。这些函数使用多个参数,参数间用逗号分开。
- 另外有一些函数不接受任何参数。在C++中,函数调用必须包括括号,即使没有参数。
- 有些函数有返回值。
- 还有一些函数没有返回值。
3、用户定义的函数
通过以下代码,可以实现通过函数名来调用用户定义的函数:
程序清单2.5 ourfunc.cpp
//ourfunc.cpp -- 定义自己的函数
#include <iostream>
void simon(int); // simon()函数原型
int main()
{
using namespace std;
simon(10); //调用simon()函数
cout << "选择一个整数:";
int count;
cin >> count;
simon(count); //再次调用
cout << "完成!" << endl;
return 0;
}
void simon(int n) //定义simon()函数
{
using namespace std;
cout << "西蒙说他有" << n << "个胡萝卜" << endl;
} //没有返回值得函数不需要返回语句
通过main()
函数两次调用simon()
函数,一次的参数为100,另一次的参数为变量count
。运行情况如下:
西蒙说他有100个胡萝卜
选择一个整数130
西蒙说他有130个胡萝卜
完成!
(1)函数格式
首先由一个函数头,然后是花括号中的函数体:
类型 函数名(参数列表)
{
语句
}
C++不允许将函数定义嵌套在另一个函数定义中。
(2)函数头
在程序清单2.2中,simon()
函数的函数头如下:
void simon(int n)
开头的void
表示没有返回值,括号中的int n
表明,使用simon()
时,应提供一个int
参数。
关键字是计算机语言中的词汇。本章使用了int
、void
、return
、double
等关键字。由于这些关键字都是C++专用的,因此不能用作他用。