第 1 章 开始学习 C++
文章目录
1.1 C++ 简介
C++ 融合了 3 3 3 种不同的编程方式:C 语言代表的过程性语言、C++ 在 C 语言基础上添加的类代表的面向对象语言、C++ 模板支持的泛型编程。笔者于 23 23 23 年暑假已经大致学过一遍 C++,但由于 C++ 知识体系过于庞大复杂,且在过去的一年内笔者基本没有使用 C++ 做过什么项目,所以希望重新梳理一遍 C++ 知识体系并记录分享。本系列基于的学习教材是 《C++ Primer Plus》,主要介绍 C++98 的特性,涵盖一些 C++11 新增的特性。本系列默认读者已经能够熟练掌握 C 语言,对于一些基本的编程知识不再赘述。
1.2 进入 C++
//myfirst.cpp
#include <iostream>
int main()
{
using namespace std;
cout << "Come up and C++ me some time." << endl;
cout << "You won't regret it!" << endl;
return 0;
}
首先介绍一下上面程序与 C 的不同。
1.2.1 C++ 预处理器和 iostream
文件
C++ 和 C 一样,也使用一个预处理器,该程序在进行主编译之前对源文件进行处理。不必执行任何特殊的操作来调用该预处理器,它会在编译程序时自动运行。
myfirst.cpp
使用了 #include
编译指令:
#include <iostream>
该编译指令导致预处理器将 iostream
文件的内容添加到程序中。这是一种典型的预处理器操作:在代码被编译之前,替换或添加文本。
1.2.2 头文件名
C 语言的传统是使用扩展名 .h
来标识头文件,但 C++ 不同:C++ 对老式 C 的头文件保留了扩展名 .h
,而 C++ 头文件则没有扩展名。有些 C 头文件被转换为 C++ 头文件,这些文件被重新命名,去掉了扩展名 .h
并在文件名称前加上前缀 c
,如下表所列:
头文件类型 | 约定 | 示例 |
---|---|---|
C++ 旧式风格 | 以 .h 结尾 | iostream.h |
C 旧式风格 | 以 .h 结尾 | math.h |
C++ 新式风格 | 没有扩展名 | iostream |
转换后的 C | 加上前缀 c ,没有扩展名 | cmath |
1.2.3 名称空间
如果使用头文件 iostream
,则应使用 using namespace std
这一条名称空间编译指令来使 iostream
中的定义对程序可用,这叫 using
编译指令。
名称空间支持是一项 C++ 特性,旨在编写大型程序以及将多个厂商现有的代码组合起来时更容易。例如,可能使用两个已经封装好的产品,而它们都包含一个名为 wanda()
的函数。这样,使用 wanda()
函数时,编译器将不知道指的是哪个版本。名称空间让厂商能够将其产品封装在一个叫做名称空间的单元中,这样就可以用名称空间的名称来指出想要使用哪个厂商的产品。如:
Microflop::wanda("go dancing?");
Piscine::wanda("a fish named Desire");
这种方式意味着在 iostream
中定义的用于输出的 cout
变量实际上是 std::cout
,而 endl
实际上是 std::endl
。因此,可以省略编译指令 using
,按照下面这样写代码:
std::cout << "Come up and C++ me some time." << std::endl;
std::cout << "You won't regret it!" << std::endl;
然而,这种方式在多数用户眼里较为繁琐,于是 using
编译指令应运而生。using namespace std
表明:可以使用所有 std
名称空间中定义的名称,而不必使用 std::
前缀。
这是一种偷懒的做法,在大型项目中是一个潜在的问题。更好的方法是只让所需的名称可用,这可以通过 using
声明来实现:
using std::cout;
using std::endl;
using std::cin;
用这些编译指令之后,便可以使用 cin、cout、endl
而不用带上 std::
前缀。
1.2.4 使用 cout
进行 C++ 输出
cout<<""Come up and C++ me some time."<<endl;
上述语句中,<<
符号表示该语句将把字符串发送给 cout
,该符号指出了信息流动的途径。cout
是一个预定义的对象(对象是类的实例),知道如何显示字符串、数字、字符等。endl
是一个特殊的 C++ 符号,表示一个重要的概念:重起一行,相当于 \n
。
初识运算符重载
学过 C 语言的读者可能注意到插入运算符
<<
和按位左移运算符<<
完全一致。这是一个运算符重载的例子,通过重载,同一个运算符将具有不同的含义,而编译器可以通过上下文来确定运算符的含义。C 语言本身也有一些运算符重载的情况。例如,&
符号既表示地址运算符,又表示按位与运算符;*
既表示乘法,又表示指针解引用。C++ 扩展了运算符重载的概念,允许为用户定义的类型重载运算符。
1.3 其他 C++ 语句
// getinfo.cpp
#include <iostream>
int main()
{
using namespace std;
int carrots;
cout << "How many carrots do you have?" << endl;
cin >> carrots;
cout << "Here are two more. ";
carrots = carrots + 2;
cout << "Now you have " << carrots << " carrots." << endl;
return 0;
}
下面是该程序运行的情况:
How many carrots do you have?
12
Here are two more. Now you have 14 carrots.
1.3.1 使用 cin
iostream
文件将 cin
定义为一个表示输入流的对象:输入时,cin
使用 >>
运算符从输入流中抽取字符。通常,需要在运算符右侧提供一个变量,以接收抽取的信息。cin
和 cout
一样都是智能对象,能够将键盘输入转换为接受信息的变量能够接受的形式。
1.3.2 使用 cout
进行拼接
cout
可以像下面这样拼接输出:
cout << "Now you have " << carrots << " carrots." << endl;
得到的输出和下面两种情况相似:
//case 1
cout<<"Now you have ";
cout<<carrots;
cout<<" carrots.";
cout<<endl;
//case 2
cout<<"Now you have ";
<<carrots;
<<" carrots.";
<<endl;
1.3.3 类简介
类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息和可对数据执行哪些操作。类之于对象就像类型之于变量。打个比方,如果说类好比所有著名演员,则对象就好比某一个著名演员,如邓超。
现在来看 cout
,它是一个 ostream
类对象。ostream
类的定义描述了 ostream
对象表示的数据以及可以对他执行的操作。同样,cin
是一个 istream
类对象,也是在 iostream
中定义的。
类是用户定义的类型,但作为用户,并没有设计 ostream
和 istream
类。就像函数可以来自函数库一样,类也可以来自类库。ostream
和 istream
就属于这种情况。
1.3.4 在多函数程序中使用 using
编译指令
当前通行的理念是:只让需要访问名称空间 std
的函数访问它。让程序能够访问 std
的方法有很多种,下面是其中
4
4
4 种。
-
将
using namespace std;
放在函数定义之前,让文件中所有的函数都能访问std
。如:#include <iostream> using namespace std; void simon(int); int main() { statement... } void simon(int n) { cout << "Simon says touch your toes " << n << " times.\n"; }
-
将
using namespace std;
放在特定的函数定义中,让该函数可以访问std
。如:void simon(int n) { using namespace std; cout << "Simon says touch your toes " << n << " times.\n"; }
-
在特定的函数中使用类似
using std::cout;
这样的编译指令,让该函数能够使用指定的元素,如cout
。 -
完全不使用
using
,而在需要使用名称空间std
中的元素时使用前缀std::
,如下所示:std::cout << "I'm using cout and endl from the std namespace" << std::endl;