C++:入门基础(1)
本章代码见:https://gitee.com/jxxx404/cpp-language-learning/commit/a3ad3222e0b101c72369a35bd1fea293261ebfcb
接下来将同步更新C++,数据结构,Linux系统以及C语言算法相关内容。如有错误欢迎指出。
1.C++发展历史
C++发展历史 C++的起源可追溯至1979年,本贾尼·斯特劳斯特鲁普(Bjarne Stroustrup)在贝尔实验室开展计算机科学与软件工程研究时,因当时项目里复杂软件开发任务,尤其是模拟和操作系统开发,察觉到像C语言这类现有语言在表达能力、可维护性和可扩展性方面存在局限,于是着手进行新语言的探索。
1983年,斯特劳斯特鲁普在C语言基础上引入面向对象编程特性,打造出C++的雏形,此时C++已具备类、封装、继承等核心面向对象概念,为后续面向对象编程发展筑牢根基,该语言也于这一年正式被命名为C++。
此后数年,C++在学界和工业界应用逐步拓展。众多高校与研究机构将其作为教学和科研的关键语言,不少企业也在产品开发中积极尝试运用C++。在此期间,C++的标准库(为开发者提供了大量现成的函数和类,方便进行各种操作,比如输入输出、字符串处理等)和模板(支持泛型编程,能编写与数据类型无关的代码,提高代码的复用性)等重要特性持续完善与发展,进一步增强了C++的实用性与灵活性。
C++的标准化工作始于1989年,当时成立了由美国国家标准协会(ANSI)和国际标准化组织(ISO)共同组成的联合标准化委员会。1994年,委员会推出首个标准化草案,此草案在保留斯特劳斯特鲁普最初定义的所有特征的前提下,新增了部分特性,让C++的功能更加丰富。 而STL(标准模板库),是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室开发的一套功能强大的软件组件集合,包含容器(如向量、列表等,用于存储数据)、算法(用于对容器中的数据进行操作,如排序、查找等)和迭代器(用于遍历容器中的元素)等部分。
在C++标准化首个草案通过后,联合标准化委员会投票通过将STL纳入C++标准的提议。尽管STL的加入极大地扩展了C++的能力,超出了其最初的定义范围,但也使得C++标准化进程有所延缓,因为需要对STL进行充分的讨论、测试和整合。
最终,1997年11月14日,联合标准化委员会通过了C++标准的最终草案,1998年,C++的ANSI/ISO标准正式投入使用,这一标准为C++的发展和应用提供了统一且规范的依据,推动C++在全球范围内得到更广泛、更一致的应用。
1.1C++版本更新
1.2有关C++23
C++一直被垢病的是一直没出网络库(networking),networking之前是在C++23的计划中的,现在C++23已经发布了,但是没有networking,网上引发了一系列吐槽。
https://zhuanlan.zhihu.com/p/107360459
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2453r0.html
2.C++参考文档
https://legacy.cplusplus.com/reference/(非官方)
https://en.cppreference.com/w/cpp.html
3.C++的重要性
3.1编程语言排行榜
TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如
Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube和Baidu(百度)统计出排名数据,只是反映某个编程语言的热门程度,并不能说明一门编程语言好不好,或者一门语言所编写的代码数量多少。
https://www.tiobe.com/
25年9月榜单:
3.2C++的应用
C++的应用领域服务器端、游戏(引擎)、机器学习引擎、音视频处理、嵌入式软件、电信设备、金融应用、基础库、操作系统、编译器、基础架构、基础工具、硬件交互等很多方面都有。
1.大型系统软件开发。如编译器、数据库、操作系统、浏览器等等
2.音视频处理。常见的音视频开源库和方案有FFmpeg、WebRTC、Mediasoup、ijkplayer,音视频开发最主要的技术栈就是C++。
3.PC客户端开发。一般是开发Windows上的桌面软件,比如WPS之类的,技术栈的话一般是C++和QT,QT是一个跨平台的C++图形用户界面(GraphicalUserInterface,GUI)程序。
4.服务端开发。各种大型应用网络连接的高并发后台服务。这块Java也比较多,C++主要用于一些对性能要求比较高的地方。如:游戏服务、流媒体服务、量化高频交易服务等
5.游戏引擎开发。很多游戏引擎就都是使用C++开发的,游戏开发要掌握C++基础和数据结构,学习图形学知识,掌握游戏引擎和框架,了解引擎实现,引擎源代码可以学习UE4、Cocos2d-x等开源引擎实现
6.嵌入式开发。嵌入式把具有计算能力的主控板嵌入到机器装置或者电子装置的内部,通过软件能够控制这些装置。比如:智能手环、摄像头、扫地机器人、智能音响、门禁系统、车载系统等等,粗略一点,嵌入式开发主要分为嵌入式应用和嵌入式驱动开发。
7.机器学习引擎。机器学习底层的很多算法都是用C++实现的,上层用python封装起来。如果你只想准备数据训练模型,那么学会Python基本上就够了,如果你想做机器学习系统的开发,那么需要学会C++。
8.测试开发/测试。每个公司研发团队,有研发就有测试,测试主要分为测试开发和功能测试,测试开发一般是使用一些测试工具(selenium、Jmeter等),设计测试用例,然后写一些脚本进行自动化测试,性能测试等,有些还需要自行开发一些测试用具。功能测试主要是根据产品的功能,设计测试用例,然后手动的方式进行测试。
4.C++学习建议
4.1C++学习难度
见“二十一天自学精通”梗:
4.2C++学习建议
我需要坚持。
5. C++的第一个程序
C++兼容C语言绝大多数的语法,所以C语言实现的helloworld依旧可以运行,C++中需要把定义文件代码后缀改为.cpp,vs编译器看到是.cpp就会调用C++编译器编译,linux下要用g++编译,不再是gcc。
不过C++也有一套自己的输入输出,严格来说,应该是这样:
6.命名空间
6.1namespace的价值
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
c语言项目类似下面程序这样的命名冲突是普遍存在的问题,C++引入namespace就是为了更好的解决这样的问题。
6.2namespace的定义
1.定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对即可,{}中
即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
前提:在同一作用域,不能定义同一变量,在不同的作用域下可以定义同一变量。
2.namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。
#include <stdio.h>
#include <stdlib.h>namespace bit
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}int main()
{return 0;
}
之前接触到的作用域为:局部域和全局域。
int a = 1;//全局域
int main()
{int a = 0;//局部域return 0;
}
相关的运用:
#include <stdio.h>
#include <stdlib.h>namespace bit
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}//没有分号;int a = 1;//全局
int main()
{// 编译器语法查找确认,默认规则先局部查找->全局查找->没有找到就报错未声明的标识符int a = 0;printf("%d\n", a);// ::域作用限定符printf("%d\n",::a);printf("%p\n",rand);// 编译器语法查找确认,指定作用域,就直接去这个域查找->没有找到就报错未声明的标识符printf("%d\n",bit::rand);printf("%p\n",bit::Add);printf("%d\n", bit::Add(1,2));//printf("%p\n", bit::add);struct bit::Node node;return 0;
}
3.C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期,命名空间域依旧是全局变量。
4.namespace只能定义在全局,当然他还可以嵌套定义。
#include <stdio.h>namespace bit
{namespace pg{int rand = 1;int Add(int left, int right){return left + right;}}namespace hg{int rand = 2;int Add(int left, int right){return (left + right) * 10;}}
}int main()
{printf("%d\n", bit::pg::rand);printf("%d\n", bit::hg::rand);return 0;
}
5.项目工程中多文件中定义的同名namespace会认为是一个namespace,不会冲突。
//stack.h
#pragma once
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>namespace st
{typedef int STDataType;typedef struct Stack{STDataType* a;int top;int capacity;}ST;void Init(ST* ps);void Destroy(ST* ps);void Push(ST* ps, STDataType x);void Pop(ST* ps);
}//stack.cpp#include"Stack.h"namespace st
{void Init(ST* ps){//...}void Push(ST* ps, STDataType x){//...}
}//queue.h
#pragma once
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>namespace queue
{typedef int QDataType;typedef struct QueueNode{int val;struct QueueNode* next;}QNode;typedef struct Queue{QNode* phead;QNode* ptail;int size;}Queue;void Init(Queue* pq);void Destroy(Queue* pq);// void Push(Queue* pq, QDataType x);// void Pop(Queue* pq);
}//queue.cpp
#include"Queue.h"namespace queue
{void Init(Queue* pq){//...}
}//test.cpp
#include"Stack.h"int main()
{st::ST s1;st::Init(&s1);st::Push(&s1, 1);st::Push(&s1, 2);st::Push(&s1, 3);return 0;
}
6.C++标准库都放在一个叫std(standard)的命名空间中。
#include<algorithm>int main()
{int a[] = { 4,1,5,7 };std::sort(a, a + 4);return 0;
}
6.3命名空间的使用
先看下方第7节。
编译查找一个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下面程序会编译报错。所以我们要使用命名空间中定义的变量/函数,有三种方式:
6.3.1指定命名空间访问,项目中推荐这种方式。
#include <iostream>// 定义一个自定义命名空间
namespace MyNamespace {int value = 2025; // 命名空间内的变量void show() { // 命名空间内的函数std::cout << "This is from MyNamespace." << std::endl;}
}int main() {// 方式1:指定命名空间访问变量std::cout << "MyNamespace::value = " << MyNamespace::value << std::endl;// 方式2:指定命名空间访问函数MyNamespace::show();return 0;
}
6.3.2using将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。
#include<iostream>
#include<algorithm>// 部分展开
using std::cout;
using std::endl;//int cout = 0;
int sort = 0;int main()
{int i = 100;double d = 1.1111;cout << "hello world" << endl; // end linecout << i << " " << d << endl;cout << i << " " << d << endl;cout << i << " " << d << endl;std::cin >> i;int a[] = { 4,1,5,7 };std::sort(a, a + 4);return 0;
}
6.3.3展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用。
#include<iostream>
using namespace std;int main()
{int i = 100;double d = 1.1111;cout << "hello world" << endl; // end linecout << i << " " << d << endl;cout << i << " " << d << endl;cout << i << " " << d << endl;return 0;
}
如果定义和库里面一样的变量,则代码错误,因此不推荐,如下:
7.C++输入&输出
1.<iostream>是Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输
出对象。
2.std:cin是istream类的对象,它主要面向窄字符(narrowcharacters(oftype char))的标准输入流。
3.std::cout是ostream类的对象,它主要面向窄字符的标准输出流。
4.std::endl是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区。
5.<<是流插入运算符,>>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)
6.使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是
C++的流能更好的支持自定义类型对象的输入输出。
7.IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这些知识我们还没有讲解,所以这里只简单认识一下C++IO流的用法。
8.cout/cin/endl等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要
通过命名空间的使用方式去用他们。
9.一般日常练习中我们可以usingnamespacestd,实际项目开发中不建议usingnamespacestd。
10.这里我们没有包含<stdio.h>,也可以使用printf和scanf,在包含<iostream>间接包含了。vs系列
编译器是这样的,其他编译器可能会报错。
#include<iostream>int main()
{int i = 100;i << 5;double d = 1.1111;// 任何变量,都转换成字符串,插入到流中// 自动识别类型std::cout << i<<'\n'<<"\n";std::cout << "hello world"<< std::endl; // end linestd::cout << i <<" "<< d << std::endl;printf("%.2f\n", d);std::cin >> i >> d;std::cout << i << " " << d << std::endl;// 类,复杂类型, IO流支持复杂类型输入输出return 0;
}
本章完。