引言
C语言作为编程基石,其高效与直接性深受开发者喜爱。然而,随着软件复杂度的增加,C++以其面向对象及高级特性成为了新的选择。我们接下来将学习C++,从C语言迈向C++。
什么是C++
C++ 是一种高级语言,由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发。它进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言,可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。
C++完善了C语言的许多缺陷,并且引入了面向对象的程序设计思想,包括面向对象的四个特性:封装,继承,多态,抽象。
C++的组成
C++作为一种强大的编程语言,其组成可以从多个维度进行解析。从核心组成部分的角度来看,C++主要由以下三个重要部分组成:
1.C++语言核心:这是C++的基础,包括了C++的基础语法和语义。例如,变量、数据类型(如整型、浮点型、字符型等)、控制结构(如if语句、循环语句等)、函数、类和对象等基本概念和特性都属于C++语言核心。这些元素共同构成了C++程序的基本框架和逻辑结构。
2.C++标准库:C++标准库提供了一系列预定义的函数和类,用于执行常见的编程任务。这些库函数和类覆盖了广泛的领域,包括字符串处理、类型转换、文件操作、时间日期处理、数学运算等。
3.标准模板库(STL):STL是C++标准库的一个重要组成部分,它提供了一系列模板类和函数,用于实现各种数据结构和算法。
我们后面的学习主要围绕这三部分进行。
C++版本更新
阶段 | 内容 |
带类的C(C with Classes) | 是在C语言的基础上增加了类(class)的机制 |
C++ 1.0 | 虚函数、函数和运算符重载、引用等概念 |
C++2.0 | 更加完善支持面向对象,新增保护成员、多重继承、对象的初始化、抽象类、静态成员以及const成员函数 |
C++3.0 | 进一步完善,引入模板,解决多重继承产生的二义性问题和相应构造和析构的处理 |
C++98 | C++官方第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美国标准化协会认可,以模板方式重写C++标准库,引入了STL(标准模板库) |
C++03 | C++标准第二个版本,语言特性无大改变,主要:修订错误、减少多异性 |
C++11 | 引入了对象移动、右值引用、lambda表达式、编译时类型识别(auto)、别名模板等现代编程语言常具备的能力 |
C++14 | 对C++11的重要补充和优化,引入了二进制文字常量、将类型推导从Lambda函数扩展到所有函数等 |
C++17 | 引入了类模板参数推导、UTF-8文字常量、fold表达式等新特性 |
C++20 | 入了许多新的特性,比如:模块(Modules)、协 程(Coroutines)、范围(Ranges)、概念(Constraints)等重大特性,还有对已有 特性的更新:比如Lambda支持模板、范围for支持初始化等 |
C++20标准中增加了很多新特性,这些特性虽然能够提高开发效率,但需要相应的编程经验和技巧来掌握。C++本身的复杂性和学习难度就较大,因此新特性的引入进一步增加了学习成本。
现在公司主流使用的是C++98与C++11两个标准。
C++在工作领域的应用
C++的应用领域服务器端、游戏(引擎)、机器学习引擎、音视频处理、嵌入式软件、电信设备、金融应用、基础库、操作系统、编译器、基础架构、基础工具、硬件交互等很多方面都有。
1. 大型系统软件开发。如编译器、数据库、操作系统、浏览器等等。
2. 音视频处理。常见的音视频开源库和方案有FFmpeg、WebRTC、Mediasoup、ijkplayer,音视频开发最主要的技术栈就是C++。
3. PC客户端开发。一般是开发Windows上的桌面软件,如WPS之类的,技术栈的话⼀般是C++和QT,QT是⼀个跨平台的 C++ 图形用户界面(Graphical User Interface,GUI)程序。
4. 服务端开发。各种大型应用网络连接的高并发后台服务。这块Java也比较多,C++主要用于⼀些对性能要求比较高的地方。如:游戏服务、流媒体服务、量化高频交易服务等。
5. 游戏引擎开发。很多游戏引擎就都是使用C++开发的,如虚幻引擎,游戏开发要掌握C++基础和数据结构,学习图形学知识,掌握游戏引擎和框架,了解引擎实现,引擎源代码可以学习UE4、Cocos2d-x等开源引擎实现。
6. 嵌入式开发。嵌入式把具有计算能力的主控板嵌入到机器装置或者电子装置的内部,通过软件能够控制这些装置。
7. 机器学习引擎。机器学习底层的很多算法都是用 C++ 实现的,上层用 python 封装起来。
8. 测试开发/测试。每个公司研发团队,有研发就有测试,测试主要分为测试开发和功能测试,测试开发⼀般是使用⼀些测试工具(selenium、Jmeter等),设计测试用例,然后写⼀些脚本进行自动化测试,性能测试等,有些还需要自行开发⼀些测试用具。功能测试主要是根据产品的功能,设计测试用例,然后手动的方式进行测试。
C++的关键字
C++有63个关键字,如下所示:
C++的第一个程序
C++兼容C语言绝大多数的语法,所以C语言实现的hello world依旧可以运行,C++中需要把定义文件代码后缀改为.cpp,vs编译器看到是.cpp就会调用C++编译器编译。
C语言代码:
#include<stdio.h>int main(){ printf("hello world\n"); return 0;}
C++的标准输入与输出函数是cin与cout,分别对应C语言的printf与scanf。但是相较于C语言,C++输入输出并不需要指定占位符,如:%d,%c等。
C++代码:
#include<iostream>using namespace std;int main(){ cout << "hello world" << endl; return 0;}
接下来我们会来分析这段代码的各个部分。
命名空间
命名空间是C++中用于组织代码的一种机制,它提供了一种将库中的名称封装起来的方法,从而避免了全局命名空间的污染。简单来说,命名空间就像是一个容器,里面可以包含函数、变量、类型等标识符(即名称),而这些标识符在命名空间外部是不可见的,除非通过特定的方式(如使用命名空间的名称作为前缀,或使用using声明/指令)来访问。
1.定义命名空间
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{ }即可,{ }中即为命名空间的成员。
基本语法:
namespace namespace_name { // 在这里声明变量、函数、类型等 }
来看个简单的例子:
namespace a{int rand = 10;}int main(){std::cout << a::rand << std::endlreturn 0;}
2.命名空间的使用
在我们定义完命名空间之后,我们需要对其进行访问。
(1)域作用限定符
域作用限定符(Scope Resolution Operator),在C++中通常使用双冒号 :: 来表示,它主要用于指定变量、函数、类型等标识符所属的特定作用域。这个操作符在C++编程中扮演着重要的角色,尤其是在处理命名冲突、访问全局变量或命名空间中的成员时。
看个简单的例子:
namespace b { int a = 10;}void func() { int a = 20; std::cout << b::a << std::endl; // 输出全局变量a的值 std::cout << a << std::endl; // 输出局部变量a的值 }
:: 通知编译器应从作用域限定符左侧的名字所示的作用域中寻找右侧那个名字,即指定访问哪个名字空间的哪个成员。当左侧为空时,默认访问的就是全局域。
例如这样:
#include<iostream>int a = 10;void func(){int a = 20;printf("%d\n", a); // 输出局部变量printf("%d\n", ::a); // 输出全局变量}int main(){ func();return 0;}
我们接下来试试访问C++标准命名空间。(cout,endl等常用函数都被定义在C++标准命名空间std中)。
#include<iostream>int main(){std::cout << "hello world" << std::endl;return 0;}
输出结果:
(2)使用using声明
using声明可以在局部作用域(如函数内部)或命名空间作用域中引入命名空间的一个或多个成员。这使得在当前作用域内可以直接使用这些成员,而不需要前缀。
使用方式为 using 命名空间名称:: 成员。
namespace c { int x = 42;}void func() { using c::x; // 引入命名空间中的一个成员 std::cout << x << std::endl; // 现在可以直接使用x }
(3)使用using namespace
由于cout,endl等常用函数都被定义在C++标准命名空间std中,我们可以使用using namespace使得命名空间中的所有成员都可以直接使用,而不需要前缀。
#include<iostream>using namespace std;int main(){ cout << "hello world" << endl; return 0;}
然而,这种做法在全局作用域或头文件中通常是不推荐的,因为它可能导致命名冲突。
日常小练习程序为了方便推荐使用。
3.命名空间的嵌套
命名空间可以嵌套定义,这意味着一个命名空间内部可以定义另一个命名空间。这种结构有助于进一步组织代码,特别是在大型项目中,它允许开发者将相关的功能或库按逻辑分组。
当访问嵌套命名空间中的成员时,需要使用外层命名空间的名称作为前缀,然后是内层命名空间的名称,最后才是成员的名称。这可以通过连续使用作用域解析运算符(::
)来实现。
来看个简单的例子:
namespace bit{int rand = 10;int Add(int num1, int num2){return num1 + num2;}namespace a{int rand = 1;}namespace b{int rand = 2;}}int main(){printf("%d\n", bit::Add(1, 1));printf("a:%d\n", bit::a::rand);printf("b:%d\n", bit::b::rand);return 0;}
4.命名空间的合并
在同一个工程中多个名称相同的命名空间,在编译时命名空间会自动合并。
namespace c{int a = 1;}namespace c{int b = 1;}//编译时会自动合并
C++的输入输出
<iostream>是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输
出对象。
std::cin 是 istream 类的对象,它主要面向窄字符的标准输入流。
std::cout 是 ostream 类的对象,它主要面向窄字符的标准输出流。
std::endl 是⼀个函数,流插入输出时,相当于插入⼀个换行字符加刷新缓冲区。
<< 是流插入运算符, >> 是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)。IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,我们在后续的学习中也会接触到。
cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要
通过命名空间的使用方式去用它们。
注意:⼀般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std。
结束语
这算是迈向C++的第一步~
感谢各位大佬的支持!!!
求点赞收藏关注!!!