C++:C++入门基础|命名空间|输入输出

Harper·Lee 2024-07-13 08:35:04 阅读 84

欢迎来到Harper·Lee的学习笔记!

博主主页传送门: Harper·Lee的博客主页!

想要一起进步的uu来后台哦!

一、什么是C++?

在此之前,我们所学习的C语言是一种结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了面向对象思想(OOP,即object oriented programming),支持面向对象的程序设计语言应运而生。

1982年,本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此: C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

image.png

二、C++的发展史

1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为 C with classes。C++的发展主要经历了以下几个阶段:

阶段 发展内容
C with classes 类及派生类、公有和私有成员、类的构造和析构、友元、内联函数、赋值运算符重载等
C++1.0 添加虚函数概念,函数和运算符重载,引用、常量等
C++2.0 更加完善支持面向对象,新增保护成员、多重继承、对象的初始化、抽象类、静态成员以及const成员函数
C++3.0 进一步完善,引入模板,解决多重继承产生的二义性问题和相应构造和析构的处理
C++98 C++标准第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美国标准化协会认可,以模板方式重写C++标准库,引入了STL(标准模板库)
C++03 C++标准第二个版本,语言特性无大改变,主要:修订错误、减少多异性
C++05 C++标准委员会发布了一份计数报告(Technical Report,TR1),正式更名C++0x,即:计划在本世纪第一个10年的某个时间发布
C++11 增加了许多特性,使得C++更像一种新语言,比如:正则表达式、基于范围for循环、auto关键字、新容器、列表初始化、标准线程库等
C++14 对C++11的扩展,主要是修复C++11中漏洞以及改进,比如:泛型的lambda表达式,auto的返回值类型推导,二进制字面常量等
C++17 在C++11上做了一些小幅改进,增加了19个新特性,比如:static_assert()的文本信息可选,Fold表达式用于可变的模板,if和switch语句中的初始化器等
C++20 自C++11以来最大的发行版,引入了许多新的特性,比如:模块(Modules)、协程(Coroutines)、范围(Ranges)、概念(Constraints)等重大特性,还有对已有特性的更新:比如Lambda支持模板、范围for支持初始化等
C++23 制定ing(中间出现一些小插曲)
C++26 ……

时间轴如下:

image.png

虽然C++技术不断地在发展,但是目前大多数的公司使用的是C++98和C++11标准。

三、C++的就业方向(涉及领域)

image.png

根据上图最新的TIOBE调查结果可知,C++、C、python都是比较热门的编程语言,发展前景比较好,因此就业前景相对广阔,一些自然也相对卷一些。在未来我们至少需要学习两门以上的编程语言,因此,不要走马观花的学习,而是要精益求精,实质性的精通掌握一两门语言。这样,上手其他语言时也会比较的得心应手。

注意:排名不能说明哪个语言好,哪个不好,每门编程语言都有适应自己的应用场景。

C++的应用领域比较广阔,主要包括以下几个领域:

软件开发。包括大型系统软件开发,例如编译器、数据库、操作系统、浏览器等,还有小型软件开发,像CAD软件开发、SDK应用开发、军工类软件开发 、数据库开发等。服务器端开发。例如一个美团接单环节:商家是否开业是否接单、上架什么菜品、如何接单、如何分配骑手、对个别不合理的行为如何举报拉黑等。游戏开发。**游戏开发要掌握C++基础和数据结构,学习图形学知识,掌握游戏引擎和框架,了解引擎实现。**比如:魔兽世界、传奇、CS、跑跑卡丁车等。嵌入式和物联网领域。嵌入式把具有计算能力的主控板嵌⼊到机器装置或者电子装置的内部,通过软件能够控制这些装置。大致上,嵌⼊式开发主要分为嵌入式应⽤和嵌入式驱动开发。常见的岗位有:嵌入式开发工程师、驱动开发工程师、系统开发工程师、Linux开发工程师、固件开发工程师等。音视频与图形处理。**数字图像处理中涉及到大量数学矩阵方面的运算,对CPU算力要求比较高,主要的图像处理算法库和开源库等都是C/C++写的;⾳视频开发最主要的技术栈就是C++。**例如OpenCV、OpenGL、Photoshop等。人工智能。人工智能(机器学习)的核心是机器学习、算法,它们大多数都是C++实现的,不仅需要很强的数学能力,同时一般都要求高学历。测试开发/测试

校招都是公司需要什么技能自己就学习什么技能的,因此要学会包装自己,有方向地调衡自己。

学习C++:![image.png](https://img-blog.csdnimg.cn/img_convert/fb93b6c50bfdc9ae273542c094146ff7.png

四、C++的关键字(C++98)

asm do if return try continue
auto double inline short typedef for
bool dynamic_cast int signed typeid piblic
break else long sizeof typename throw
case enum mutable static union wchar_t
catch explicit namespace static_cast unsigned default
char export new struct using friend
class extern operator switch virtual register
const false private template void true
const_cast float protected this volatile while
delete goto reinterpret_cast

五、C++的输入与输出

:Input Output Stream的缩写,是标准的输⼊输出流库,定义了标准的输⼊、输出对象。新版本的c++为了区分C语言,没有加入 .h 的后缀。std:是C++官方库内容定义的命名空间。cin(标准输入对象) :console in的缩写,是istream类型的对象,控制台输入,可自动识别类型,包含在头文件中;cout(标准输出对象):console ourt的缩写,是ostream类型的对象,控制台输出,可自动识别类型,包含在头文件中;根据前两条,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的),不用像C语言中的printf/scanf那样手动控制格式。endl:endline,是一个函数,相当于换行,包含在头文件中;<<:流插⼊运算符,>>:流提取运算符。它们都涉及到运算符重载的相关知识,而且不是只能输入输出在控制台。(C语言用这两个运算符做位运算左移/右移)cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。C语言中可以通过占位符控制浮点数的精度,但是C++比较复杂,可直接使用C语言的方式,C语言和C++相辅相成。这⾥我们没有包含<stdio.h>,也可以使用printf和scanf,在包含间接包含了。vs系列编译器是这样的,其他编译器可能会报错。

<code>#include <iostream>

#include <stdlib.h>

using namespace std;//全部展开std标准库

int main()

{

int a = 0;

double b = 3.0;

char c = 'x';

cout << "Harper·Lee" << endl;

//cout:标准输出对象(控制台)

// << :流插入运算符;>>:流提取运算符

//endl:end line,相当于换行符

std::cout << a << endl;//因为上面已经展开了,就不需要指定了

cout << a << " " << b << endl;

//可以自动识别变量的类型

cin >> a;

cin >> b >> c;

cout << a << endl;

cout << &a << endl;

cout << b << " " << c << endl;

//cin:标准输入对象(键盘)

return 0;

}

运行结果:

image.png

<code>#include<iostream>

using namespace std;

int main()

{

// 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码

// 可以提⾼C++IO效率

ios_base::sync_with_stdio(false);

cin.tie(nullptr);

cout.tie(nullptr);

return 0;

}

六、C++参考文档

https://legacy.cplusplus.com/reference/?(非C++官方文档)

https://zh.cppreference.com/w/cpp?(中文版)

https://en.cppreference.com/w/?(英文官方版)

书籍参考:C++Primer(作为语法字典) / Effective C++侯捷(应用经验和坑) / STL源码剖析(库底层、中后期)。

image.png

C++学起来很难是必然的,因为就语法而言,C++要解决C语言的一些问题,也要追求效率,此外历史发展比较早,发展历程总会有些许坎坷。

七、命名空间

7.1 C++中的域

C++中域包括:函数局部域,全局域,命名空间域,类域。域影响的是编译时语法查找⼀个变量/函数/类型出处**(声明或定义)**的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。

请注意:

在同一个域里面不能重复定义同一个名称的变量。在不同的域里面能定义同一个名称的变量。

7.2 域作用限定符(::)

**符号 :: **作用:可以避开局部的,直接访问全局的。:: 域作用限定符左边是空白就默认代表访问的是全局域。用法:直接在变量前加上限定符即可。在 .cpp文件中才支持域作用限定符,.c 文件中是不支持域作用限定符的。在C语言中,当局部变量与全局变量冲突时,优先使用局部变量。

<code>//test.cpp

#include <stdio.h>

int a = 10;//全局变量

int main()

{

int a = 5;

printf("%d\n", a);

//通过局部域作用限定符访问指定命名空间的变量

printf("%d\n",::a);//::符号前面是空白(有无空格都一样),默认代表访问的是全局域

return 0;

}

image.png

7.3 命名空间的由来

7.3.1 什么是命名空间?

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

7.3.2 为什么会有命名空间?

有如下的代码:

<code>#include <stdio.h>

#include <stdlib.h>

int rand = 10;

int main()

{

printf("%d\n", rand);

return 0;

}//我们定义的变量名和库里面的名称冲突了

报错:

image.png

首先我们分析一下为什么会有这样的错误:

报错原因: 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”。rand在cpp文件里面是定义的一个变量,但是rand在stdlib库中代表一个函数,就出现了重定义的情况,在这里就叫做命名冲突。(注意:rand作为函数时,函数名默认是函数的地址。)

解决方法:这种情况在C语言中可以通过重新修改变量的名字,使其不再与关键字或者函数名重名即可;在c++中,可以通过命名空间解决。

<code>#include <stdio.h>

#include <iostream>

#include <stdlib.h>

namespace Harper//定义了一个命名空间域

{

int rand = 10;//在bit命名空间里面,rand仍然是全局变量

}

void func()

{

printf("%p\n", rand);//访问的是函数指针,函数名默认是函数的地址,%d改成%p

printf("%d\n",Harper::rand);//打印访问Harper命名空间中变量rand的值

}

int main()

{

func();

return 0;

}

运行结果:

image.png

7.4 命名空间的定义

namespace关键字定义全局命名空间域,后面跟命名空间的名字,然后接⼀对 {} 即可,{}中即为命名空间的成员。

<code>#include <iostream>

#include <stdlib.h>

namespace Harper

{

int year = 19;

}

int main()

{

printf("%d\n", Harper::year);

return 0;

}

运行结果:

image.png

7.5 命名空间的性质

命名空间中可以定义变量/函数/类型等。

<code>#include <iostream>

#include <stdlib.h>

namespace Harper

{

// 命名空间中可以定义变量/函数/类型

int rand = 10;

int Add(int left, int right)

{

return left + right;

}

struct Node

{

struct Node* next;

int val;

};

}

int main()

{

//函数调用

printf("%d\n", Harper::Add(1, 1));

//结构体

struct Harper::Node p1;//而不是Harper:: struct Node p1;

//因为对象是Node,struct是关键字

return 0;

}

命名空间需要定义一个域:命名空间域。命名空间域不会影响其中变量的生命周期。为了避免冲突,c++把标准库的内容定义到了官方的命名空间中,这个命名空间叫做std。std是C++官方库内容定义的命名空间。

7.6 命名空间的嵌套定义

namespace只能定义在全局,但是它可以嵌套定义。就像多个项目组里会定义出一样的名称,可以通过namespace解决;但如果在一个项目组即同一个命名空间里面,各个分工合并代码时就出现冲突了,这样就可以通过在同一个命名空间里嵌套再次定义命名空间。

#include <iostream>

#include <stdlib.h>

namespace Harper

{

namespace Lee

{

int rand = 10;

int Add(int left, int right)

{

return left + right;

}

}

namespace Aururo

{

int Sub(int left, int right)

{

return left * right;

}

}

}

int main()

{

printf("%d\n", Harper::Lee::Add(1, 1));

printf("%d\n", Harper::Aururo::Sub(2, 3));

return 0;

}

运行结果:

image.png

7.7 命名空间的合并

同一个工程中允许存在多个相同名称的命名空间,编译器最后会将其合并在同一命名空间中。不同⽂件中可以定义同名namespace,他们会默认合并到⼀起,就像同⼀个namespace⼀样。

<code>#include <iostream>

#include <stdlib.h>

namespace Harper

{

int rand = 5;

}

namespace Harper

{

int ret = 1;

}

int main()

{

printf("%d\n", Harper::rand + Harper::ret);

return 0;

}//文件中的同理

运行结果:

image.png

7.8 命名空间的使用

编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。因此我我们可以通过三三种方式访问命名空间。

7.8.1 域作用限定符访问

指定命名空间访问,项目中比较推荐这种方式。

<code>#include <stdio.h>

#include <stdlib.h>

namespace Harper

{

int rand = 10;

}

void func()

{

printf("%d\n", Harper::rand);

}

7.8.2 using部分展开

使用using展开命名空间中某个频繁使用的成员,项目中经常访问的不存在冲突的成员可使用此法。

#include <iostream>

#include <stdlib.h>

namespace Harper

{

int year = 19;

int a = 6;

}

using Harper::a;//展开常用的a

int main()

{

printf("%d\n", Harper::a);

return 0;

}

7.8.3 using namespace整个展开

使用using namespace展开整个命名空间,在项目中并不推荐,冲突的风险很大,可在日常的小练习中使用全部展开,将这个繁琐的指定命名空间过程化简。

#include <iostream>

#include <stdlib.h>

//展开整个命名空间

namespace Harper

{

int year = 19;

}

using namespace Harper;

int main()

{

printf("%d\n", Harper::year);

return 0;

}

注意:

展开命名空间:编译器将命名空间的域拆开寻找(相当于去掉域这个束缚);展开头文件:将头文件的内容拷贝过来;using namespace相当于把命名变量的隔离墙给拆了,就会有命名冲突的风险。

喜欢的uu记得三连支持一下哦!

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。