【C++】新手入门指南

 
> 🍃 本系列为初阶C++的内容,如果感兴趣,欢迎订阅🚩
> 🎊个人主页:[小编的个人主页])小编的个人主页
>  🎀   🎉欢迎大家点赞👍收藏⭐文章
> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍


 

目录

🐼C++的发展史

🐼命名空间

🐼命名空间的使用

🐼C++输入输出

🐼缺省参数

🐼函数重载

🐼引用

 🐼引用的使用

 🐼const引用

 🐼指针和引用的关系


🐼C++的发展史

🌟C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)感受到了面对项目中复杂的软件开 发任务,特别是模拟和操作系统的开发工作,他感受到了现有语言(如C语言)在表达能力、可维护性 和可扩展性方面的不足😑

于是1983年,Bjarne Stroustrup C语言的基础上添加了面向对象编程 的特性,设计出了C++语言的雏形😄 ,此时的C++已经有了 类、封装、继承 等核心概念,为后来的⾯向对象编程奠定了基础。这⼀年该语言被 正式命名为C++。
于是C++的标准化工作于1989年开始,在完成C++标准化的第⼀个草案后不久, STL 被投票
包含到C++标准中。
⭐️ 于是C++进行了一系列版本更新,如图:

 
🌟值得肯定的是: C++兼容C语言绝大多数的语法 ,所以C语言实现的程序依旧可以运行, C++中需要把定义文件 代码后缀改为.cpp ,vs编译器看到是.cpp就会调用C++编译器编译,linux下要用g++编译,不再是gcc

🐼命名空间

✨在C/C++中,会使用到大量变量,函数,类,结构体等。这些变量,函数,类在全局变量中,会引起命名冲突。而在C++中引入了命名空间,就是管理当前标识符的名称进行本地化,以免造成命名冲突。在C++中引入了namespace关键字来解决这种问题。

比如在之前可能遇到这种问题:

int rand = 1;
int main()
{printf("%d", rand);return 0;
}

会显示报错:“rand”: 重定义;以前的定义是“函数”。

这正是由于编译器在库中找到了和全局变量一样的名字,造成报错。

👀那我们应该怎么解决这个问题呢?

这需要使用namespace关键字,使用规则: namespace加命名空间的名字后面跟一对花括号{}。如果我们能改变编译器的查找规则,让编译器从我们定义的域中查找变量,函数,类等。这使namespace定义的域和全局域就相互独立起来了,在不同的域中定义相同的变量,函数,类,结构体等,编译器在查找时,根据命名空间的名字,到对应的空间中查找,就不会造成访问冲突等问题了。本质上,namespace是定义出⼀个域,这个域跟全局域相互独立,不受影响。通过修改编译器的查找逻辑,各个域互不影响。

注意:

1.命名空间域和类域不影响变量生命周期。

2.在项目文件中namespace关键字定义命名空间可以重名,不过编译器认为属于同一块空间。

3.namespace只能定义在全局。支持嵌套定义。

而访问命名空间中的元素,需要使用命名空间名字+::。

在把C++标准库都放到了一个std(standard)的命名空间中:

比如:

namespace li
{int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
int main()
{printf("%d\n", li::rand);printf("%d\n", li::Add(10, 20));return 0;
}

😾解释: 在上述例子中 ,我们定义了一个li的命名空间,里面分别有变量rand,函数Add,结构体。我们通过li::rand来访问在li命名空间中rand变量,以及函数调用。而在这里std::cout和std::endlC++,std是C++标准库的命名空间,具体下面输入输出会讲解。

🐼命名空间的使用

✌️在前面的分享中,我们知道命名空间本质是定义了一个本地域。编译器在查找时,默认会在局部和全局变量中查找,不会到命名空间中查找。所以我们需要掌握命名空间的使用的三种方式:

1.指定命名空间访问。就如刚刚上述例子,li::rand.在项目中推荐,安全性好。

2.使用using将命名空间中全部成员展开。这种方式风险较大,安全性不好,适用于平时练习比较方便。

3.使用using将命名空间中某个成员展开。这种方式取了前两种方式的优点,如果有一个不重名成员频繁使用,可以考虑这种方式。

这里举例:

namespace li
{int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
//指定命名空间访问
int main()
{printf("%d\n", li::rand);printf("%d\n", li::Add(10, 20));return 0;
}
//使用using将命名空间中全部成员展开
using namespace li;
int main()
{printf("%d\n", li::rand);printf("%d\n", li::Add(10, 20));return 0;
}
//使用using将命名空间中某个成员展开
using li::Add;
int main()
{printf("%d\n", li::rand);//频繁调用Addprintf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));printf("%d\n", li::Add(10, 20));return 0;
}

🐼C++输入输出

⭐️ <iostream> 是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。
  1. std::cin是 istream 类的对象,主要是窄字符的标准输入流。
  2. std::cout是 ostream 类的对象,主要是窄字符的标准输出流。
  3. std::endl是一个函数,用于流插入输出,相当于一个换行字符刷新缓存区。
  4. <<是流插入运算符,>>是流提取运算符

 在使用C++输入输出不用指定格式。在C++中输入输出都是自动识别的变量数据类型(本质上是通过函数重载实现的)、

cout,cin,endl都是在属于C++标准库中的,而C++标准库是放在一个std的命名空间中。

在上述我们分享交代了C++使用命名空间的方法。

虽然我们这里没有使用<stdio.h>,但是依旧可以使用printf,scanf,原因是<iostream>

间接包含了。在刚刚的例子中,我们将printf都换成cout。
namespace li
{int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
//使用using将命名空间中某个成员展开
using li::Add;
int main()
{std::cout << li::rand << std::endl;//频繁调用Addstd::cout << Add(10,20)<< std::endl;	std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;std::cout << Add(10,20)<< std::endl;return 0 ;
}

🐼缺省参数

⭐️还是由于在面向对象编程中的不方便,在C++中提出了缺省参数这个概念。

缺省参数是函数声明或定义时为参数指定的一个缺省值。在函数调用时,如果指定了实参,就使用实参,否则,就使用缺省值。

⭐️缺省值分为全缺省和半缺省,全缺省就是所有形参都给缺省值,半缺省就是部分形参给缺省值。在给缺省值时,C++规定,必须从右向左给缺省值,不能跳跃给缺省值。

注意:

缺省值不能在函数声明和定义同时给,只能在函数声明确定缺省值。

缺省值用法:

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 = 10, int c = 20)
{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(100);Func2(100, 200);Func2(100, 200, 300);return 0;
}

🐼函数重载

⭐️在C++中,支持了同名函数在同一作用域出现,但是要求同名函数的参数不同,可以是参数类型或个数,如果同名函数的返回值不同不能构成重载。比如在之前我们实现计算器,对于加法,可能有整数+整数,浮点数+浮点数等。现在同名函数的调用使用起来就很方便了,这样的做法使得C++使用起来更灵活,这也反映了C++的多态


int Add(int x, int y)
{return x + y;
}double Add(double x, double y)
{return x + y;
}
using namespace std;
int main()
{cout << Add(10, 20) << endl;cout << Add(10.1, 20.1) << endl;return 0;
}

🐼引用

⭐️在我们日常生活中,经常会给别人取别名,比如 苏轼,别称包括“东坡居士”、“苏子瞻”、“苏洵之子”等,东坡居士是苏轼,苏子瞻是东坡居士,苏洵之子是苏子瞻,他们都是苏轼。但对他的别名都是苏轼这个人,没有其他人。
在C++中,引入了引用这个概念,引用是给变量取别名,并没有定义一个新变量,也没有创建新的空间。
类型& 引用别名 = 引用对象;
这里&和C语言取地址操作符是一样的,但是含义完全不同,大家要区别开
比如:
using namespace std;
int main()
{int a =10;int& ra = a;int& rra = a;int& rrra = a;//ra rra rrra地址完全相同cout << &ra << endl;cout << &rra << endl;cout << &rrra << endl;int x = 0;int& b = x;int& c = b;int& d = c;++d;cout << &x << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;cout << x << " " << b << " " << c << " " << endl;return 0;
}

这里x,b,c,d都是同一片空间。

 🐼引用的使用

  1. 首先,需要注意,引用一旦引用了一个实体,就不能引用其他实体。
  2. 可以有多个引用引用同一个变量。
  3. 引用在定义时必须初始化。

例:

#include<iostream>
using namespace std;
int main()
{int a = 10;// 编译报错:“ra”: 必须初始化引⽤//int& ra;int& b = a;int c = 20;// 这并不是让b引用c,因为C++引用不能改变指向,// 这是⼀个赋值,相当于给a指向的空间赋值b = c;cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << b << endl;cout << c << endl;cout << a << endl;return 0;
}

🍏引用在使用时主要有两种用途,引用传参或引用作返回值。 优点:减少拷贝提高效率和改变引用对象时同时改变被引用对象

引用传参跟指针传参功能是类似的,引用传参相对更方便⼀些。

比如在交换两个数的值,在C语言需要取地址,使用指针。在C++中,引用这方面用起来方便多了。

using namespace std;
void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}
int main()
{int x = 0, y = 1;cout << x << " " << y << endl;Swap(x, y);cout << x << " " << y << endl;return 0;
}

我们在之前不带头单链表创建时形参是这样的:

void ListPushBack(LTNode** phead, int x)

test.cpp
LTNode* plist = NULL;
ListPushBack(plist,1);
typedef struct ListNode
{
int val;
struct ListNode* next;
}LTNode, *PNode;
// 指针变量也可以取别名,这⾥LTNode*& phead就是给指针变量取别名
// 这样就不需要⽤⼆级指针了,相对⽽⾔简化了程序
void ListPushBack(LTNode** phead, int x)
void ListPushBack(LTNode*& phead, int x)

1.我们这里可以拆开来看,首先,变量可以拿来引用,那么,指针也可以拿来引用。引用plist的指针,形参可以用LTNode*& phead来接收,其中,LTNode*是phead引用的类型。就像引用int&b = a(int为a的类型)。

2.这里用typedef简写了结构体指针*PNode,这表示指向结构体的指针,等价于LTNode*

最后,也可以写作:void ListPushBack(PNode& phead, int x);

 🐼const引用

🍊在引用时,我们可能会触碰以下情形:

比如:int& rb = a*3;  double d = 12.34;  int& rd = d;在这些场景下,如10,a*3,12.34都保存在一个临时对象(临时对象:编译器需要把一个空间暂存表达式的结果放在一个未命名的对象中)中,而对于int& rd = d发生类型转换,也是需要借助临时变量C。而C++规定临时对象具有常性,不能修改,所以这里就触发了权限放大,必须要用常引用才可以。如果引用对象是需要放在临时变量就有常性的,都需要我们使用常引用,权限可以平行或缩小,权限不能放大。

int main()
{//权限放大,无法从“const int”转换为“int &”const int a = 10;//int& ra = a;//正确示范:const int& ra = a;// 编译报错:error C3892: “ra”: 不能给常量赋值//ra++;// 这⾥的引用是对b访问权限的缩小int b = 20;const int& rb = b;// 编译报错:error C3892: “rb”: 不能给常量赋值//rb++;//权限不能放大const int* pa = &a;//int* pb = &a;//权限可以缩小int* pc = &b;const int* ppc = pc;return 0;
}

 🐼指针和引用的关系

🍒在c++中,指针和引用的使用是紧密相关,不可分割的。

语法上:

  1. 引用在定义时必须初始化,指针建议初始化,但不必须。

  2. 引用一旦有了实体,就不可以再指向其他实体,但是指针可以不断地指向其他对象。

  3. 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。

  4. 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。

  5. 引用是一个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
  6. sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个byte,64位下是8byte)。

在汇编层:

指针和引用的实现本质上是一样的。

int main()
{int a = 10;int* pa = &a;int b = 10;int& d = b;return 0;
}

感谢你看到这里,如果觉得本篇文章对你有帮助,点个赞👍 吧,你的点赞就是我更新的最大动力⛅️🌈 ☀️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58949.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序开发进阶之路-AI编程助手

之前&#xff0c;我独自一人开发了一个名为“心情追忆”的小程序&#xff0c;旨在帮助用户记录日常的心情变化及重要时刻。从项目的构思、设计、前端&#xff08;小程序&#xff09;开发、后端搭建到最终部署&#xff0c;所有环节都由我一人包办。经过一个月的努力&#xff0c;…

Cursor的chat与composer的使用体验分享

经过一段时间的试用&#xff0c;下面对 Composer 与 Chat 的使用差别进行总结&#xff1a; 一、长文本及程序文件处理方面 Composer 在处理长文本时表现较为稳定&#xff0c;可以对长文进行更改而不会出现内容丢失的情况。而 Chat 在更改长的程序文件时&#xff0c;有时会删除…

【笔记】自动驾驶预测与决策规划_Part6_不确定性感知的决策过程

文章目录 0. 前言1. 部分观测的马尔可夫决策过程1.1 POMDP的思想以及与MDP的联系1.1.1 MDP的过程回顾1.1.2 POMDP定义1.1.3 与MDP的联系及区别POMDP 视角MDP 视角决策次数对最优解的影响 1.2 POMDP的3种常规解法1.2.1 连续状态的“Belief MDP”方法1. 信念状态的定义2. Belief …

Latex公式转换编辑网站

https://editor.codecogs.com/ https://www.latexlive.com/home## https://simpletex.cn/ai/latex_ocr https://webdemo.myscript.com/views/math/index.html# 参考 https://latex.91maths.com/ https://web.baimiaoapp.com/image-to-latex https://blog.csdn.net/qq_45100…

注意力机制的目的:理解语义;编码器嵌入高纬空间计算;注意力得分“得到S*V”;解码器掩码和交叉注意力层用于训练;最终的编码器和输出实现大模型

目录 注意力机制的目的:理解语义中的它是小白兔 词编码器嵌入高纬空间 计算注意力得分“得到S*V” 权重QKV:连接权重 训练阶段使用解码器:翻译后的语句 解码器掩码和交叉注意力层用于训练 最终的编码器和输出实现大模型 Transformer模型中,QKV QKV的作用 举例说明…

【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值

设置方法 mini 中提供了 imageUrlLoaderOption 和 postcss.url 。 其中&#xff1a; config.limit 和 imageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js &#xff0c; 值的写法要 &#xff08;&#xff09;KB * 1024。 config.maxSize 服务于 postcss-url 的…

【MatLab手记】 --从0到了解超超超详过程!!!

文章目录 MatLab笔记一、命令行窗口二、变量命名规则三、数据类型1. 数字2. 字符与字符串3. 矩阵3.1 矩阵创建3.2 矩阵的修改和删除3.3 矩阵的拼接与重构重排3.4 矩阵的运算方法3.5 矩阵的下标 4. 元胞数组&#xff08;类似数据容器&#xff09;5. 结构体 四、逻辑与流程控制五…

实现uniapp-微信小程序 搜索框+上拉加载+下拉刷新

pages.json 中的配置 { "path": "pages/message", "style": { "navigationBarTitleText": "消息", "enablePullDownRefresh": true, "onReachBottomDistance": 50 } }, <template><view class…

IDM扩展添加到Edge浏览器

IDM扩展添加到Edge浏览器 一般情况下&#xff0c;当安装IDM软件后&#xff0c;该软件将会自动将IDM Integration Module浏览器扩展安装到Edge浏览器上&#xff0c;但在某些情况下&#xff0c;需要我们手动安装&#xff0c;以下为手动安装步骤 手动安装IDM扩展到Edge浏览器 打…

AndroidStudio-常用布局

一、线性布局LinearLayout 线性布局内部的各视图有两种排列方式: 1.orientation属性值为horizontal时&#xff0c;内部视图在水平方向从左往右排列。 2.orientation属性值为vertical时&#xff0c;内部视图在垂直方向从上往下排列。 如果不指定orientation属性&#xff0c;…

Pr 入门系列之八:使用关键帧(上)

不论是固定效果、标准效果或是第三方效果&#xff0c;都可以通过改变属性的值来达到效果控制的目的。 任何动画要表现运动或变化&#xff0c;前后至少要给出属性值的两个不同的关键状态&#xff0c;称之为“关键帧” Keyframe。 而中间状态的变化和衔接&#xff0c;则是由计算机…

万字长文解读深度学习——循环神经网络RNN、LSTM、GRU、Bi-RNN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

qt QMovie详解

1、概述 QMovie 是 Qt 框架中用于处理动画文件的类。它支持多种动画格式&#xff0c;包括 GIF 和一些常见的视频格式&#xff08;尽管对视频格式的支持依赖于底层平台&#xff09;。QMovie 类主要用于在 QLabel 或 QGraphicsView 等控件中显示动画。通过加载动画文件&#xff…

ip addr show

本文内容来自智谱清言 ip addr show 是 Linux 系统中用于显示网络接口配置的命令。这个命令属于 iproute2 软件包&#xff0c;该软件包在大多数 Linux 发行版中都是预安装的。ip addr show 命令可以用来查看所有网络接口的当前配置&#xff0c;或者指定某个特定接口的配置。 …

【ESP32】ESP-IDF开发 | 低功耗管理+RTC唤醒和按键唤醒例程

1. 简介 ESP32支持5种低功耗模式&#xff0c;低功耗管理单元包括调压器、功耗控制器、电源开关单元、电源域隔离单元 (Isolation Cell) 等部分。 1.1 RTC单元 RTC单元是ESP32低功耗管理的核心&#xff0c;可用于管理低功耗模式的进入和退出&#xff0c;控制时钟源、PLL、电源开…

重学 Android 自定义 View 系列(三):自定义步数进度条

前言 本篇文章主要是实现仿QQ步数View&#xff0c;很老的一个View了&#xff0c;但技术永不落后&#xff0c;开搂&#xff01; 最终效果如下&#xff1a; 1. 结构分析 QQStepView 主要由三个元素组成&#xff1a; 显示一个圆环进度条&#xff0c;通过外环和内环的角度变化来…

Spring中的过滤器和拦截器

Spring中的过滤器和拦截器 一、引言 在Spring框架中&#xff0c;过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是实现请求处理的两种重要机制。它们都基于AOP&#xff08;面向切面编程&#xff09;思想&#xff0c;用于在请求的生命周期…

查缺补漏----用户上网过程(HTTP,DNS与ARP)

&#xff08;1&#xff09;HTTP 来自湖科大计算机网络微课堂&#xff1a; ① HTTP/1.0采用非持续连接方式。在该方式下&#xff0c;每次浏览器要请求一个文件都要与服务器建立TCP连接当收到响应后就立即关闭连接。 每请求一个文档就要有两倍的RTT的开销。若一个网页上有很多引…

C++之vector类的模拟实现

片头 嗨~小伙伴们&#xff0c;今天我们来一起学习关于C的vector类的模拟实现&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 一、基本框架 namespace bit {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;// 针对const修…

流体力学ansys Fluent二次开发scheme_eval模块剖析

在ANSYS Fluent的二次开发中&#xff0c;scheme_eval 是 Scheme 编程语言中一个非常重要的模块&#xff0c;它允许用户执行动态的 Scheme 表达式和函数&#xff0c;从而扩展 Fluent 的功能。scheme_eval 模块通常与 Fluent 的计算和自定义脚本操作紧密结合。下面我们会对这个模…