【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.rhkb.cn/news/468564.html

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

相关文章

ElasticSearch备考 -- Cross cluster replication(CCR)

一、题目 操作在cluster1&#xff08;local&#xff09;中操作索引task&#xff0c;复制到cluster2&#xff08;remote&#xff09;中 二、思考 CCR 我们可以对标MySQL 理解为为主从&#xff0c;后者备份。主节点负责写入数据&#xff0c;从/备节点负责同步时主节点的数据。 …

IDEA在编译时: java: 找不到符号符号: 变量 log

一、问题 IDEA在编译的时候报Error:(30, 17) java: 找不到符号符号: 变量 log Error:(30, 17) java: 找不到符号 符号: 变量 log 位置: 类 com.mokerson.rabbitmq.config.RabbitMqConfig 二、解决方案 背景&#xff1a;下载其他同事代码时&#xff0c;第一次运行&#xff0c…

一文熟悉新版llama.cpp使用并本地部署LLAMA

0. 简介 最近是快到双十一了再给大家上点干货。去年我们写了一个大模型的系列&#xff0c;经过一年&#xff0c;大模型的发展已经日新月异。这一次我们来看一下使用llama.cpp这个项目&#xff0c;其主要解决的是推理过程中的性能问题。主要有两点优化&#xff1a; llama.cpp …

[翻译]ANSI X9.24-3-2017

目录 1 目的 2 范围 2.1 应用 3 参考文献 4 术语和定义 4.1 高级加密标准&#xff08;AES&#xff09; 4.2 AES 4.3 算法 4.4 ANSI 4.5 基础推导密钥(BDK) 4.6 BDK 4.7 BDK ID 4.8 加密密钥 4.9 加密密钥同步 4.10 密码强度 4.11 派生 4.12 派生标识符(ID) 4…

使用 GitHub Actions 部署到开发服务器的详细指南

使用 GitHub Actions 部署到开发服务器的详细指南 在本篇博客中&#xff0c;我们将介绍如何使用 GitHub Actions 实现自动化部署&#xff0c;将代码从 GitHub 仓库的 dev 分支自动部署到开发服务器。通过这种方式&#xff0c;可以确保每次在 dev 分支推送代码时&#xff0c;服…

Docker安装部署RabbitMQ

1. Docker环境准备 1.1 安装Docker 在开始Docker安装部署RabbitMQ之前&#xff0c;确保您的系统环境已经满足Docker的运行要求。以下是在不同操作系统上安装Docker的步骤和命令行演示。 对于Linux系统 在基于Debian的系统&#xff08;如Ubuntu&#xff09;上&#xff0c;您…

UniAPP u-popup 禁止背景滑动

增加class .NoScroll {overflow: hidden;position: fixed; }在外层div上增加该class判断条件

ubuntu 24.04运行chattts时cuda安装错误原因分析

使用ubuntu 24.04&#xff0c;按照2noise/ChatTTS官方流程安装依赖时报错。ChatTTShttps://github.com/2noise/ChatTTS 这是因为cuda版本不对&#xff0c;ChatTTS目前的版本&#xff0c;要求支持cuda 12.4及以上&#xff0c;但是如果nvidia显卡驱动版本较老&#xff0c;无法支…

spring-security(记住密码,CSRF)

注册PersistentTokenRepository PersistentTokenRepository实现类 InMemoryTokenRepositoryImpl基于内存实现 JdbcTokenRepositoryImpl基于数据库实现 基于内存实现 Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { Bean publi…

iOS问题记录 - 503 Service Temporarily Unavailable

文章目录 前言开发环境问题描述问题分析解决方案最后 前言 最近有个项目经历了大改动&#xff0c;本地测试没什么问题&#xff0c;于是准备通过打包机打包用于内部测试的包&#xff0c;然后问题就来了。 开发环境 Xcode: 16.1Fastlane: 2.219.0 问题描述 问题出在登录苹果…

linux-vlan

# VLAN # 1.topo # 2.创建命名空间 ip netns add ns1 ip netns add ns2 ip netns add ns3 # 3.创建veth设备 ip link add ns1-veth0 type veth peer name ns21-veth0 ip link add ns3-veth0 type veth peer name ns23-veth0 # 4.veth设备放入命名空间,启动接口 ip link set n…

HTB:Precious[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机TCP端口进行开放扫描 使用curl访问靶机80端口 使用ffuf爆破一下子域 使用浏览器访问该域名 使用curl访问该域名响应头 使用exiftool工具查看该pdf信息 横向移动 USER_FLAG&#xff1a;adf5793a876a190f0c08b3b6247cec32…

链表归并与并集相关算法题

两递增归并为递减到原位 假设有两个按元素递增次序排列的线性表&#xff0c;均以单链表形式存储。将这两个单链表归并为一个按元素递减次序排列的单链表&#xff0c;并要求利用原来两个单链表的节点存放归并后的单链表 算法思想 因为两链表已按元素值递增次序排列&#xff0…

山东布谷科技:关于直播源码|语音源码|一对一直播源码提交App Store的流程及重构建议

自从YY、六间房开启国内聊天室和秀场等网红盛行的网络红利时代以来&#xff0c;紧随其后国内各大音视频平台相应出现&#xff0c;先有映客花椒等直播平台的风头正劲&#xff0c;后有功能板块更丰富的头条抖音Tiktok等&#xff0c;盈利功能点不仅仅有直播PK连麦等礼物打赏功能&a…

C++ 【STL容器系列(一)】vector的使用

1.介绍 vector是STL中的容器之一&#xff08; STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。&#xff09;&#xff0c;STL的容器有非常多&#x…

机器学习5_支持向量机_原问题和对偶问题——MOOC

目录 原问题与对偶问题的定义 定义该原问题的对偶问题如下 在定义了函数 的基础上&#xff0c;对偶问题如下&#xff1a; 综合原问题和对偶问题的定义得到&#xff1a; 定理一 对偶差距&#xff08;Duality Gap&#xff09; 强对偶定理&#xff08;Strong Duality Theo…

华为eNSP:mux-vlan

一、什么是mux-vlan&#xff1f; Mux-vlan 是一种多路复用的虚拟局域网&#xff08;Virtual Local Area Network&#xff09;技术。它将多个不同的VLAN流量转发到同一个物理端口&#xff0c;从而实现VLAN间的互通。 在传统的以太网环境中&#xff0c;每个VLAN通常都有一个独立…

YOLOPv2论文翻译

YOLOPv2: Better, Faster, Stronger for Panoptic Driving Perception 摘要 在过去的十年中&#xff0c;多任务学习方法在解决全景驾驶感知问题方面取得了令人鼓舞的成果&#xff0c;既提供了高精度又具备高效能的性能。在设计用于实时实际自动驾驶系统的网络时&#xff0c;这…

【C/C++】memcpy函数的使用

零.导言 当我们学习了strcpy和strncpy函数后&#xff0c;也许会疑惑整形数组要如何拷贝&#xff0c;而今天我将讲解的memcpy函数便可以拷贝整形数组。 一.memcpy函数的使用 memcpy函数是一种C语言内存函数&#xff0c;可以按字节拷贝任意类型的数组&#xff0c;比如整形数组。 …

Matlab轻松烟雾检测

小编经验分享&#xff1a;如何使用Matlab进行烟雾检测 烟雾检测是一项重要的安全技术&#xff0c;它可以帮助我们及时发现火灾风险并采取相应的措施。在这篇文章中&#xff0c;小编将和大家分享如何使用Matlab进行烟雾检测的经验。希望这些经验对大家在实际应用中能够有所帮助…