一、C++发展历史
C++是一种广泛使用的高级编程语言,它由丹麦计算机科学家比雅尼·斯特劳斯特卢普(Bjarne Stroustrup)于1979年在AT&T贝尔实验室开始设计开发,并在1983年正式命名。
C++的发展历程大致如下:
1. 起源(1979年-1983年):斯特劳斯特卢普开始着手“C with Classes”的研发工作,旨在为C语言添加面向对象的特性。这门新语言保留了C语言的高效性和可移植性,同时引入了类、简单继承、内联机制、函数默认参数以及强类型检查等特性。
2. 早期发展(1983年-1985年):1983年,“C with Classes”语言正式更名为C++。这一时期加入了许多重要特性,如虚函数、函数重载、引用机制(符号为&)、const关键字以及双斜线的单行注释(从BCPL语言引入)。
3. 第一个版本发布(1985年):斯特劳斯特卢普的C++参考手册《C++ Programming Language》出版,同年C++的商业版本问世。由于当时C++没有正式的语言规范,这本书成为了业界的重要参考。
4. 版本更新(1989年):引入了多重继承、保护成员以及静态成员等语言特性。
5. 标准化(1998年):C++标准委员会发布了C++语言的第一个国际标准—ISO/IEC 14882:1998,即C++98。标准模板库(STL)也被纳入该标准。
6. 修订与改进(2003年):针对C++98版本中的问题进行修订,发布了C++03。
7. 新特性引入(2011年):新的C++标准C++11面世,Boost库对该版本影响很大,一些新模块直接衍生于Boost中的相应模块。C++11引入了众多新特性,包括正则表达式、完备的随机数生成函数库、新的时间相关函数、原子操作支持、标准线程库、一种新的for语法(能够和某些语言中的foreach语句达到相同效果)、auto关键字、新的容器类、更好的union支持、数组初始化列表的支持以及变参模板的支持等。
8. 持续发展(2014年、2017年等):2014年发布了C++14标准,对C++11进行了一些小的改进和修复;2017年发布了C++17标准,引入了变量模板、文件系统库、并行算法等新特性。之后C++标准仍在不断更新和发展,以适应新的编程需求和技术趋势。 C++通过不断吸收新特性和改进,逐渐成为一种功能强大、灵活且高效的编程语言,被广泛应用于系统软件、游戏开发、嵌入式系统、大型数据库和交易系统等众多领域。
二、C++在⼯作领域中的应⽤
C++在以下工作领域中有广泛的应用:
1. 游戏开发:C++因其高效的性能和对硬件的直接控制能力,常用于开发大型游戏的核心引擎和关键模块。
2. 操作系统开发:如 Windows、Linux 等操作系统的部分关键组件是用 C++编写的。
3. 嵌入式系统:在诸如智能家居设备、汽车电子系统、工业控制系统等嵌入式领域,C++能够高效地利用有限的资源。
4. 金融交易系统:需要处理大量数据和高并发交易,对性能要求极高,C++能够满足这种需求。
5. 科学计算和数值分析:用于编写高性能的数值计算库和模拟软件。
6. 图形图像处理:在图像和视频处理软件、计算机辅助设计(CAD)等领域,C++能够实现复杂的算法和高效的图形渲染。
7. 网络编程:开发高性能的网络服务器和网络应用程序。
8. 数据库系统:数据库的底层引擎和优化部分常使用 C++。
9. 虚拟现实和增强现实:构建实时渲染和交互的系统。
总之,在对性能、效率和资源控制要求较高的工作领域,C++都有着重要的地位。
三、参考文档
说明:第⼀个链接不是C++官⽅⽂档,标准也只更新到C++11,但是以头⽂件形式呈现,内容⽐较易看好懂。后者是C++官网文档,信息很全,更新到了最新的C++标准,但是 相⽐第⼀个不那么易看。所以,我们可以结合使用。
四、C++程序
C++语言是如何产生的?是咱们的祖师爷对于C语言的不满时所为做也。因此,C++兼容C语言。我们开始学C语言,我们启蒙代码为:
#include<stdio.h> int main() { printf("hello world\n"); return 0; }
在C++编译器中这个代码也可以运行。但,这毕竟不是正经的C++代码。就好比:普通话是我们的官方语言,但我说你们当地方言你肯定可以听明白。这毕竟不是官方的,我们肯定要明白官方的如何书写,代码如下:
#include<iostream> using namespace std; int main() { cout << "hello world\n" << endl; return 0; }
这里的代码看不明白,很正常,就好比你开始学C语言看不懂代码一样,跟着我学习脚本你肯定能看明白,接下来开始我们的学习吧!
五、命名空间
1.什么是命名空间
在C语言我们学习函数的时候,我们学习过生命周期这个概念。那么,什么是生命周期呢?生命周期通常指的是一个对象或变量从创建到销毁所经历的时间段。那么,命名空间是什么?咱们可以这样理解:在这个空间的生命周期内,对这个空间内的全部标识符起一个名字,可对其进行引用,可类似与C语言中的结构体。可用于解决以下情况:
#include<stdio.h> #include<stdlib.h>//此处不包此头文件代码可正常运行,那该如何解决此处情况呢? int main() { int rand = 10; printf("%d\n", rand);//此处编译不通过原因为:在不包头文件前为变量,包含后为函数。 return 0; }
解决方法如下:
#include<stdio.h> #include<stdlib.h> namespace example { // 命名空间中可以定义变量/函数/类型 int rand = 10; }//注意:此处无;号 int main() { printf("%d\n",example::rand ); return 0; }
我们可用命名空间来解决此类问题。
2.命名空间定义
定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中 即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下⾯的rand不在冲突了。
C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响 编译查找逻辑,还会影响变量的声明周期,命名空间域和类域不影响变量声明周期。
namespace只能定义在全局,当然他还可以嵌套定义。
项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
C++标准库都放在⼀个叫std(standard)的命名空间中。
3.命名空间使⽤
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以 下⾯程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:
指定命名空间访问,项⽬中推荐这种⽅式。
using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
对于第二种方式类似于C语言中头文件,在C语言进行编译时,编译器会把头文件里的东西拷贝过来。
六、C++输⼊&输出
可参考以下代码:
#include<iostream> using namespace std; int main() { int a = 1; double b = 0.1; char c = 'a'; std::cout << a << " " << b << " " << c << endl;//可多个输出 cout << a << " " << b << " " << c << endl;//此处可省略std原因为:std为全展开 std::cin >> a; cin >> b >> c;//可多个输入 cout << a << " " << b << " " << c << endl; return 0; }
• <iostream>是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输 出对象。
• std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输 ⼊流。
• std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。
• std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。
• >是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
• 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊ 输出可以⾃动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是 C++的流能更好的⽀持⾃定义类型对象的输⼊输出。
• IO流涉及类和对象,运算符重载、继承等很多⾯向对象的知识,这些知识我们还没有讲解,所以这 ⾥我们只能简单认识⼀下C++ IO流的⽤法,后⾯我们会有专⻔的⼀个章节来细节IO流库。
• cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要 通过命名空间的使⽤⽅式去⽤他们。
• ⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std。
七、缺省参数
• 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参 则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把 缺省参数也叫默认参数)
• 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。
• 带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。
• 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
缺省参数可这样理解:你传参数时,这个函数有参数,不会使用这个函数本身的参数,使用你传来的参数;但当你传空参时,便会用函数本身参数。简单来讲便是:有的话,不考虑你;没有的话,便考虑你。(是不是像某个群体,这里希望各位不要成为缺省参数(手动[doge]))。
可结合以下代码理解:
#include<iostream> using namespace std; void Func(int a = 0) { cout << a << endl; } int main() { Func(); // 没有传参时,使⽤参数的默认值 Func(10); // 传参时,使⽤指定的实参 return 0; }
#include<iostream> using namespace std; // 全缺省 void Func1(int a = 10, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } //半缺省 void Func2(int a, int b = 20, int c = 30)//此处缺省要连续,不可跳跃且要从右向左,不可从左向右 { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } int main() { Func1(); Func1(1);//此处参数从左向右替换 Func1(1, 2); Func1(1, 2, 3); //Func2(); 此处参数不可传空,原因a未定义 Func2(100); Func2(100, 200); Func2(100, 200, 300); return 0; }
八、函数重载
在C语言中,以加法函数为例,要是传参类型不同,我们就要对其进行重写一个函数且要用不同的函数名,是不是过于麻烦?这里简单说一下面向对象的三大特点之一——多态的思想来解决。
C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同 名函数的。
参考以下代码:
#include<iostream> using namespace std; //1.参数类型不同型 int Add(int left, int right) { cout << "int Add(int left , int right)" << endl; return left + right; } double Add(double left, double right) { cout << "double Add(double left , double right)" << endl; return left + right; } //2.参数个数不同 void Func() { cout << "Func()" << endl; } void Func(int a) { cout << "Func(int a)" << endl; } //3. 参数顺序不同 void F(int a, char b) { cout << "F(int a, char b)" << endl; } void F(char b, int a) { cout << "F(char b , int a)" << endl; } //注:返回值不同不能作为重载条件,因为无法区分 //void f() //{ // ; //} //int f() //{ // return 0; //} //以下两个函数虽然构成重载,但会有歧异,编译器无法明白调谁,无法运行 void f() { cout << "f()" << endl; } void f(int a = 10) { cout << "f(int a)" << endl; } int main() { Add(10, 20); Add(10.1, 20.2); Func(); Func(10); F(10, 'a'); F('a', 10); return 0; }
最后:
今天的学习到这里就结束了,希望各位读者下去后能多练,不要因为简单从而对自己要求降低。