本章概述
C++发展历史
- 简介:在C语言的学习中咱们讲过了C语言的发展史,让大家对C语言有了感性的认知。现在咱们也延续传统——从C++的发展史讲起。C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)在贝尔实验室从事计算机科学和软件工程的研究工作。面对项目中复杂的软件开发任务,特别是模拟和操作系统的开发工作,他感受到了现有语言(如C语言)在表达能力、可维护性和可扩展性方面的不足。1983年,Bjarne Stroustrup在C语言的基础上添加了面向对象编程的特性,设计出了C++语言的雏形,此时的C++已经有了类、封装、继承等核心概念,为后来的面向对象编程奠定了基础。这一年该语言被正式命名为C++。在随后的几年中,C++在学术界和工业界的应用逐渐增多。一些大学和研究所开始将C++作为教学和研究的首选语言,而一些公司也开始在产品开发中尝试使用C++。这一时期,C++的标准库和模板等特性也得到了进一步的完善和发展。C++的标准化工作于1989年开始,并成立了一个ANSI和ISO(International Standards
Organization)国际标准化组织的联合标准化委员会。1994年标准化委员会提出了第⼀个标准化草案。在该草案中,委员会在保持斯特劳斯特卢普最初定义的所有特征的同时,还增加了部分新特征。在完成C++标准化的第⼀个草案后不久,STL(Standard Template Library)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室公作时所开发出来的。在通过了标准化第⼀个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的提议。STL对C++的扩展超出C++的最初定义范围。虽然在标准中增加STL是个很重要的决定,但也因此延缓了C++标准化的进程。1997年11月14日,联合标准化委员会通过了该标准的最终草案。1998年,C++的ANSI/IS0标准被投入使用。 - 总结:
C++
的诞生就是为了弥补C语言中的一些缺陷,而且功能比C语言还要强大。对于什么是类和对象,我们会在后面的博客中继续讲解的,大家先不用刻意深究它们。给大家看一下C++之父的图片,认识一下祖师爷: - C++版本的更新:给大家展示一个表格,里面详细的介绍了它的版本更新过程:
上面的表格所列出的内容有点晦涩,我给大家展示一个发展脉络图:
上面字体加粗的部分,表示C++当时的版本在那个时代的影响很大,表示当时的版本在那个时代特好用。现在很多企业都使用的是C++98
和C++11
版本。我们主要使用的是C++11
版本进行讲解。
C++的重要性体现
- 语言排行榜:TIOBE排⾏榜是根据互联⽹上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube和Baidu(百度)统计出排名数据,只是反映某个编程语言的热门程度,并不能说明一门编程语言好不好,或者一门语言所编写的代码数量多少。大家点击连接查看最新排行榜:https://www.tiobe.com/tiobe-index/
从排行榜上可以看出C++的重要性。 - C++在工作邻域中的应用:C++的应用领域服务器端、游戏(引擎)、机器学习引擎、音视频处理、嵌入式软件、电信设备、金融应用、基础库、操作系统、编译器、基础架构、基础工具、硬件交互等很多方面都有。
C++学习建议和书籍推荐
- C++的学习难度:首先第⼀个问题,C++难学吗?首先在这里告诉大家C++是一个相对难学难精的语言,相比其他⼀些语言,学习难度要高一些要陡峭一些,这里有历史包袱的问题,也有语言本身设计和发展历史的问题。网上以前⼀直流传下面这个21天内自学精通C++的梗。给大家看看哈:
大家注意一个细节哈——主人公的头发越来越少(哈哈哈哈哈),这个漫画间接的说明了想精通C++是很难的,说明了这个语言确实不太好学。不过,大家也别担心,虽然咱们不能精通C++,但是咱们能掌握它就OK了,大家平时多努力一下,攻克它。 - C++学习建议:个人的建议是,C语言的基础要扎实,因为C++就是对C语言的不足进行改善的,再在此基础上增加了新的语法,所以C语言的基础务必要扎实。要把C++基础语法概念弄懂,要勤于敲代码。对于当前的内容,理解就OK了,不要太深究,因为知识都是串连性的,为了讲清楚本章的知识点,就会用到后面的知识点,所以不要深究,我们后面都会讲到的。
- 学习书籍推荐:我给大家推荐这三本书,这三本书是我的老师(杭哥)推荐的:
给大家讲一下,这三本书的各个特点: - C++Primer:主要讲解语法,经典的语法书籍,前后中期都可以看,前期如果自学看可能会有点晦涩难懂,能看懂多少看懂多少,就当预习,学了咱们的博客后,中后期作为语法字典,非常好用。
- STL源码剖析:主要从底层实现的角度结合STL源码,庖丁解牛式剖析STL的实现,是侯捷老师的经典之作。可以很好的帮助我们学习别人用语法是如何实现出高效简洁的数据结构和算法代码,如何使用泛型封装等。让我们不再坐井观天,闭门造车。
- Effctive C++:本书也是侯捷⽼师翻译的,本书有的一句评价,把C++程序员分为看过此书的和没看过此书的。本书主要讲了55个如何正确高效使用C++的条款,建议中后期可以看⼀遍,工作1-2年后再看⼀遍,相信会有不⼀样的收获。
希望以上推荐的书籍对大家有所帮助。
C++的输入&输出
- C++的第一个程序:先给大家说个情况,C++是兼容C语言的大部分语法的,所以是可以在C++的环境中写C语言代码的。C++中需要把定义文件代码的后缀改为
.cpp
,VS编译器看到是.cpp
就会调用C++编译器进行编译。在这里给大家提个别的知识点:在Linux下要用g++编译,不再是gcc。 因为C++兼容C语言的大部分语法,所以我先给大家展示一下在C++的环境下写的C语言代码,进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
printf("hello,world\n");
return 0;
}
结果运行图:
代码正常运行。写到这里,有人就会有疑问了,既然C++包含了C的大部分语法,那么为什么会大费周章的搞那么难学的C++呢?之前,咱们说过——C++的出现就是为了弥补C语言中的一些不足,接下来给大家展示一个C语言中的不足点,进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int rand = 10; //定义一个全局变量
int main()
{
printf("%d\n", rand);
return 0;
}
结果运行图:
在这里就会报错,报错的原因是rand
重定义。因为在<stdlib.h>
这个头文件里,已经声明的有一个rand
的函数,当我们再声明同一个名字时,就会出现重命名错误。如果在实际项目工程中,不同的项目是由不同的程序员来写的,这就可能会导致重命名的错误,这个缺点C语言是无法解决的。所以呢,C++对其进行了完善,就会用到一个新的关键字——namespace。
- namespace的价值:
namespace
被称为命名空间。在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多命名冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace
关键字的出现就是针对这种问题的。用namespace(命名空间),就可以解决我们上面所写的代码出现的报错。给大家展示一下它的用法格式,进行代码展示:
// namespace 的使用格式 ,它的格式与结构体的格式很类似。
namespace 命名
{
member1;
member2;
}
我们对代码进行命名空间,就不会出错了,进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
namespace bit
{
int rand = 10;
}
int main()
{
printf("%d\n", rand);
return 0;
}
结果运行图:
发现代码不再报错。但是,你会发现输出的结果与预期的不同。这是为什么呢?讲到这里就不得不提一个知识点了。
- 编译器的查找规则:编译器在编译的时候,遇到变量,函数或类型时,要知道它们的命名或定义(就是要知道它们的出处),编译器会先在局部查找,后在全局查找。当在局部没找到时侯,就会跑到全局去查找。我们没用命名空间(namespace)的时候,rand就属于全局范围内,而此时头文件<stdlib.h>里面的rand函数也属于全局范围内,这个时候就会冲突,编译器不知道你调用的是函数rand还是整型变量rand,就会报错。namespace就是定义了一个新的域,这个域就会使里面的东西与全局隔开,编译器就不会进里面查找了,这样就不会冲突了。所以,当我们命名空间后,编译器就只会找到头文件<stdlib.h>中的rand函数。在C语言中讲过,函数名就是地址,所以打印的就是这个函数的地址。我们用
%p
打印能看的更清楚,如图所示: - namespace的定义:
- 1.C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
- 2.namespace只能定义在全局,当然它还可以嵌套。
- 3.项目工程中,多个文件中定义的同名的namespace会自动合并成一个namespace,不会冲突的。
- 4.C++的标准库都放在
std(standard)
命名空间中。防止我们与它的标准库发生冲突。
- 给大家进行代码展示:
namespace bit //namespace的嵌套使用
{
int rand = 10;
namespace wwp
{
int a = 10;
}
}
// namespace里面什么都可以放
namespace bit
{
int rand=10; //定义变量
int add(int x,int y) //函数
{
return x+y;
}
struct bot //定义结构体
{
int i;
char arr[100];
};
}
项目工程中,多个文件中定义的同名的namespace会自动合并成一个namespace,不会冲突的。
//test.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
namespace bit
{
int rand = 10;
}
int main()
{
printf("%p\n", rand);
return 0;
}
//test.h文件
namespace bit
{
int i = 10;
int add(int x,int y) //函数
{
return x+y;
}
}
//...
void STint(void);
void STACK(int x,int y);
//...
-'::'
域操作符:编译器不会到namespace里面去查找,那么我们该怎样访问里面的数据呢?这就要提到一个操作符了——域操作符。我给大家展示一下它是怎么用的:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
namespace bit
{
int rand = 10;
}
int main() 通过bit::rand进行数据的访问
{
printf("%d\n", bit::rand);
return 0;
}
结果运行图:
命名空间嵌套的时候,就是多次使用域进行数据的访问,还可以访问函数等。在这里重点强调一下域访问结构体的特别之处,给大家看一下代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
namespace bit
{
int rand = 10;
struct bot //定义结构体
{
int i;
char arr[100];
};
}
int main()
{
printf("%d\n", bit::rand);
bit::struct bot st; //定义结构体变量
return 0;
}
结果运行图:
发现会报错,为什么呢?namespace
本质上是解决C语言中的命名冲突问题,所以域操作符指定的是变量名,函数名和结构体名等。给大家展示一下正确的结构体的域操作访问方式,进行代码展示:
//正确的域操作访问结构体的方式
struct bit::bot st; //定义结构体变量
结果运行图:
- C++自己的输入&输出方式:咱们在前面讲过,C++兼容C语言的大部分语法,也就是说scanf和printf函数都可以在C++环境中继续使用。既然都学C++了,那么我们肯定要用C++的语法呀。
- 1.
< iostream >
是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。 - 2.
std::cin
是istream
类的对象,它主要面向窄字符(narrow characters (of type char))的标准输入流。 - 3.
std::cout
是ostream
类的对象,它主要面向窄字符的标准输出流。 - 4.
std::endl
是⼀个函数,流插入输出时,相当于插入⼀个换行字符加刷新缓冲区,具有换行的效果。 - 5.
<<
是流插入运算符,用于cout
。>>
是流提取运算符,用于cin
。(C语言还用这两个运算符做位运算左移/右移)。 - 6.使用C++输入输出更方便,不需要像printf/scanf输⼊输出时那样,需要手动指定格式,C++的输⼊。
- 7.输出可以自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是C++的流能更好的支持自定义类型对象的输入输出。
- 8.IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这些知识我们还没有讲解,所以这里我们只能简单认识⼀下C++ IO流的用法,后面我们会有专门的一个章节来细节IO流库。
- 9.
cout/cin/endl
等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。 - 10.⼀般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std。
- 11.这里我们没有包含<stdio.h>,也可以使用printf和scanf,在包含间接包含了。vs系列编译器是这样的,其他编译器可能会报错。
- 1.
- cin输入流:cin是个库函数,前面咱们讲过,C++把标准库都放在命名空间std里面了,所以用
std::cin
进行访问,给大家展示一下代码:
#include <iostream>
int main()
{
int i = 0;
std::cin >> i; //用插入符 >>
printf("i=%d\n",i); //printf可以混用的
return 0;
}
结果运行图:
- cout输出流:进行代码展示:
#include <iostream>
int main()
{
int i = 0;
std::cin >> i;
//printf("i=%d\n",i)
std::cout << "i=" << i; //用输出符 <<
return 0;
}
结果运行图:
- endl换行函数:和
' \n'
的效果一样,进行代码展示:
#include <iostream>
int main()
{
int i = 0;
int b = 20;
//std::cin >> i;
//printf("i=%d\n",i)
std::cout << "i=" << i<<std::endl;
std::cout << "b=" << b<<'\n';
return 0;
}
结果运行图:
- 总结:
cin,cout
和endl
都是库函数,它们的原理都很复杂,咱们会在后面讲解的 由于C++包含C语言的大部分语法,所以在C++环境中可以混用。
彩蛋时刻!!!
歌曲:《Tomorrow》放松一下吧!!!
每章一句:人生是旷野,四面八方都是方向!
感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!