【C++】新手入门指南(下)

文章目录

前言

一、引用

1.引用的概念和定义

2.引用的特性

3.引用的使用

4.const引用

5.指针和引用的关系

二、内联函数

三、nullptr

总结


前言

这篇续上篇的内容新手入门指南(上),继续带大家学习新知识。如果你感兴趣欢迎订购本专栏。


一、引用

1.引用的概念和定义

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。如:在水浒传里,林冲,外号豹子头,宋江叫"铁牛",他们都有外号,而外号的作用跟引用一样,相当于给一个变量取别名。

类型& 引用别名 = 引用对象;

using namespace std;
int main()
{int a = 3;int& b = a;//这里&符号表示引用取别名int& c = a;int& d = b;cout << &a << endl;//012FF88C //这里&符号表示取地址cout << &b << endl;//012FF88Ccout << &c << endl;//012FF88Ccout << &d << endl;//012FF88C//每个变量地址是一样的return 0;
}

注:C++中为了避免引入太多的运算符,会复用C语言的一些符号,这里引用也和取地址使用了同一个符号&,大家注意区分使用。

2.引用的特性

1.引用在定义时必须初始化
引用需要初始值设定值,不然在编译时不知道引用指向哪个变量导致报错
using namespace std;
int main()
{
//错误写法:int a=10;int& b;
//正确写法:int a = 10;int& b = a;return 0;
}

2.一个变量可以有多个引用

一个变量可以被多个引用指向,每个引用表示这个变量的不同别名

using namespace std;
int main()
{int a = 3;int& b = a;int& c = a;int& d = b;return 0;
}

3.引用一旦引用一个实体,再不能引用其他实体

一旦引用初始化为某个变量后,就不能指向其他变量

using namespace std;
int main()
{int x = 4, y = 5;int& z = x;z=y;//这里是把变量y赋值给引用z指向的变量x,不是把引用c又指向变量yreturn 0;
}

3.引用的使用

引用主要有两种用法是 引用传参 引用做返回值 ;优点: 减少拷贝提高效率和改变引用对象时同时改变被引用对象

引用做参数的时候,可以避免传值时的拷贝开销,提高效率。

//引用传参
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;
}

引用做返回值的时候,在取栈顶时可以直接用引用做返回值,这样出函数作用域对象还可以用。提高效率和可以修改返回对象

using namespace std;
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST& rs, int n = 4)
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
}// 栈顶
void STPush(ST& rs, STDataType x)
{//assert(rs);// 满了, 扩容if (rs.top == rs.capacity){printf("扩容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}rs.a = tmp;rs.capacity = newcapacity;}rs.a[rs.top] = x;rs.top++;
}//取栈顶
//引用做返回值
int& STTop(ST& rs)
{return rs.a[rs.top - 1];
}

4.const引用

在使用引用会出现这种情况,int& rb = a*3; double d = 12.34; int& rd = d;

a*3 和12.34 保存在⼀个临时对象中, int& rd = d 发生类型转换 ,在类型转换中会产⽣临时对象存储中间值,rb和rd引用的都是临时对象。C++规定临时对象具有常性,不能修改。因此这里权限被放大,需用常引用才可以。 所以如果引用对象是需要放在临时变量就有常性的,就需要使用常引用,权限可以缩小、平移但不能放大。
using namespace std;
int main()
{//权限不能放大:const可以把变量变常量,不能常量变变量const int a = 10;//int& ra = a;//权限可以平移://const int& ra = a;//权限可以缩小://因为const起常量的作用,所以rb虽然和b是同一个地址,但是rb不能改大只能往比b小的改int b = 20;const int& rb = b;//对于指针也是一样//权限不能放大const int* pa = &a;//int* ppa = pa;//权限可以缩小int* pb = &b;const int* ppb = pb;return 0;
}

5.指针和引用的关系

  1. 引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间
  2. 引用在定义时必须初始化,指针建议初始化,但不是必须的。
  3. 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在任何时候可以改变指向对象。
  4. 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
  5. sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8个字节)
  6. 引用不存在空引用,比指针更安全,指针很容易出现空指针和野指针的问题。

二、内联函数

在C语言中,我们了解宏的定义和用法,在实现宏时会发现宏有很多弊端,比如在宏写一个加法函数 #define ADD(a, b) ((a) + (b))  时,因为宏容易出错在语法上会出“为什么里层要加括号” 、“为什么外层要加括号”以及“为什么不能加分号”等问题。 因此C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试;所以设计 inline内联函数 来代替C的宏函数。
用inline修饰的函数叫做内联函数。 编译时C++编译器会在调用的地方展开内联函数,这样调用内联 函数就需要建立栈帧了,就可以提高效率。
注:vs编译器 debug版本下面默认是不展开inline的,这样方便调试,debug版本想展开需要设置一下以下两个地方。

从汇编层上看内联函数是否展开,在VS编译器上是默认不展开的,但设置一下是会展开的。

#include<iostream>
using namespace std;
inline int Add(int x, int y)
{int ret = x + y;ret += 1;ret += 1;return ret;
}
int main()
{// 可以通过汇编观察程序是否展开// 有call Add语句就是没有展开,没有就是展开了int ret = Add(1, 2);cout << Add(1, 2) * 5 << endl;return 0;
}

没设置之前不展开:

设置之后展开:

inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。 inline适用于频繁调用的短小函数 ,对于递归函数,代码相对多一些的函数,加上inline也会被编译器忽略。
inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。 
因为分离在两个文件,会导致预处理替换;编译时会出现语法错误;调用时,声明和定义在两个文件中,在找声明时,通过链接找到符号表,这时找不到定义,就会出现链接错误
例子如下:
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{f(10);return 0;
}

会发生链接错误,编译报错:无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z)

因为函数的声明和定义分离,在链接时出错从而编译报错。

三、nullptr

在C语言中,NULL本质是一个宏。

C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。
不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过f(NULL)调用指针版本的 f(int*)函数,但是由于NULL被定义成0,调用了f(int x),因此与程序的初衷相悖。f((void*)NULL); 调用会报错。
#include<iostream>
using namespace std;
void f(int x)
{cout << "f(int x)" << endl;
}
void f(int* ptr)
{cout << "f(int* ptr)" << endl;
}
int main()
{f(0);// 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int
x),因此与程序的初衷相悖。f(NULL);f((int*)NULL);// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型// f((void*)NULL);f(nullptr);return 0;
}

运行结果:

因此,C++11中引入nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。


总结

非常感谢大家阅读完这篇博客。希望这篇文章能够为您带来一些有价值的信息和启示。如果您发现有问题或者有建议,欢迎在评论区留言,我们一起交流学习。

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

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

相关文章

uniapp-商城-33-shop 布局搜索页面以及u-search

shop页面上有一个搜索&#xff0c;可以进行商品搜索&#xff0c;这里我们先做一个页面布局&#xff0c;后面再来进行数据i联动。 1、shop页面的搜索 2、搜索的页面代码 <navigator class"searchView" url"/pagesub/pageshop/search/search"> …

SAP 采购订单如何防止开票数量 大于 收货数量呢

配置点如下&#xff1a; 事务码&#xff1a;OMRM&#xff0c;配置如下 当过账开票的数量 大于收货数量的时候会提示如下&#xff1a;

Kotlin 的 suspend 关键字

更多相关知识 Kotlin 的 suspend 关键字是 Kotlin 协程的核心组成部分&#xff0c;它用于标记一个函数可以被挂起&#xff08;暂停执行&#xff09;并在稍后恢复执行&#xff0c;而不会阻塞线程。 理解 suspend 的作用需要从以下几个方面入手&#xff1a; 1. 允许非阻塞的异步…

UDS诊断协议iso-14229 15765

Diagnostic request 形式多种: 1.SID+DID 2.SID+Sub-Func+DID 3.SID+Sub-Func SID占1个Byte,Sub-func占一个Byte,DID通常两个Byte eg.10 01 (SID+Sub-Func) 10 03 05 02 (SID+Sub-Func+DID) 22 02 00 (SID+DID) 肯定响应抑制位 抑制正响应信息除非是收到NRC 0x78的情况下 不…

记录一次使用面向对象的C语言封装步进电机驱动

简介 (2025/4/21) 本库对目前仅针对TB6600驱动下的42步进电机的基础功能进行了一定的封装, 也是我初次尝试以面向对象的思想去编写嵌入式代码, 和直流电机的驱动步骤相似在调用stepmotor_attach()函数和stepmotor_init()函数之后仅通过结构体数组stepm然后指定枚举变量中的id即…

[创业之路-376]:企业法务 - 创业,不同的企业形态,个人承担的风险、收益、税费、成本不同

在企业法务领域&#xff0c;创业时选择不同的企业形态&#xff0c;个人在风险承担、收益分配、税费负担及运营成本方面存在显著差异。以下从个人独资企业、合伙企业、有限责任公司、股份有限公司四种常见形态展开分析&#xff1a; 一、个人承担的风险 个人独资企业 风险类型&…

GNOME桌面隐藏回收站和分区

dconf-editor 搜索 trash&#xff0c;关闭 show-trash 搜索 volumes&#xff0c;关闭 show-volumns

准确--Tomcat更换证书

具体意思是&#xff1a; Starting Coyote HTTP/1.1 on http-8080: HTTP 连接器&#xff08;端口 8080&#xff09;启动成功了。严重: Failed to load keystore type PKCS12 with path conf/jlksearch.fzsmk.cn.pfx due to failed to decrypt safe contents entry: javax.crypt…

禁止ubuntu自动更新

由于ubuntu server和desktop版本都默认 启动了&#xff0c;自动更新内核的操作。这对于生 产环境来说是不友好的。容易导致亿赛通 无法启动 默认开启了内核自动更新所以我们关闭自 动内核更新。 1.禁止更新执行 sudo apt-mark hold linux-image-generic linux-headers-generic…

vue3 + element-plus中el-drawer抽屉滚动条回到顶部

el-drawer抽屉滚动条回到顶部 <script setup lang"ts" name"PerformanceLogQuery"> import { ref, nextTick } from "vue"; ...... // 详情 import { performanceLogQueryByIdService } from "/api/performanceLog"; const onD…

【重走C++学习之路】16、AVL树

目录 一、概念 二、AVL树的模拟实现 2.1 AVL树节点定义 2.2 AVL树的基本结构 2.3 AVL树的插入 1. 插入步骤 2. 调节平衡因子 3. 旋转处理 4. 开始插入 2.4 AVL树的查找 2.5 AVL树的删除 1. 删除步骤 2. 调节平衡因子 3. 旋转处理 4. 开始删除 结语 一、概念 …

char32_t、char16_t、wchar_t 用于 c++ 语言里存储 unicode 编码的字符,给出它们的具体定义

&#xff08;1&#xff09; #include <iostream> #include <string>int main() { std::u16string s u"C11 引入 char16_t"; // 定义 UTF-16 字符串for (char16_t c : s) // 遍历输出每个 char16_t 的值std::cout << std::hex << (…

redis数据类型-基数统计HyperLogLog

redis数据类型-基数统计HyperLogLog 文档 redis单机安装redis常用的五种数据类型redis数据类型-位图bitmap 说明 官网操作命令指南页面&#xff1a;https://redis.io/docs/latest/commands/?nameget&groupstringHyperLogLog介绍页面&#xff1a;https://redis.io/docs…

逻辑思维:从混沌到秩序的理性推演在软件开发中的应用

引言 在软件开发的过程中&#xff0c;逻辑思维就像是开发者的“GPS导航”&#xff0c;帮助我们从混沌的需求中找到清晰的解决方案。想象一下&#xff0c;如果没有逻辑思维&#xff0c;我们可能会在需求的海洋中迷失方向&#xff0c;最终写出一堆“看似聪明但毫无意义”的代码。…

Spring AI Alibaba Graph基于 ReAct Agent 的天气预报查询系统

1、在本示例中&#xff0c;我们仅为 Agent 绑定了一个天气查询服务&#xff0c;接收到用户的天气查询服务后&#xff0c;流程会在 AgentNode 和 ToolNode 之间循环执行&#xff0c;直到完成用户指令。示例中判断指令完成的条件&#xff08;即 ReAct 结束条件&#xff09;也很简…

HCIP(综合实验2)

1.实验拓补图 2.实验要求 1.根据提供材料划分VLAN以及IP地址&#xff0c;PC1/PC2属于生产一部员工划分VLAN10,PC3属于生产二部划分VLAN20 2.HJ-1HJ-2交换机需要配置链路聚合以保证业务数据访问的高带宽需求 3.VLAN的放通遵循最小VLAN透传原则 4.配置MSTP生成树解决二层环路问题…

使用 rebase 轻松管理主干分支

前言 最近遇到一个技术团队的 dev 环境分支错乱&#xff0c;因为是多人合作大家各自提交信息&#xff0c;导致出现很多交叉合并记录&#xff0c;让对应 log 看起来非常混乱&#xff0c;难以阅读。 举例说明 假设我们有一个项目&#xff0c;最初develop分支有 3 个提交记录&a…

使用openssl为localhost创建自签名

文章目录 自签名生成命令安装安装证书浏览器证书管理器 自签名 生成命令 使用openssl生成私钥和证书。 openssl req -x509 -newkey rsa:4096 -nodes -days 365 -subj "/CNlocalhost" -addext "subjectAltNameDNS:localhost" -keyout cert.key -out cer…

AI编程助手Cline之快速介绍

Cline 是一款深度集成在 Visual Studio Code&#xff08;VSCode&#xff09; 中的开源 AI 编程助手插件&#xff0c;旨在通过结合大语言模型&#xff08;如 Claude 3.5 Sonnet、DeepSeek V3、Google Gemini 等&#xff09;和工具链&#xff0c;为开发者提供自动化任务执行、智能…

1.微服务拆分与通信模式

目录 一、微服务拆分原则与策略 业务驱动拆分方法论 • DDD&#xff08;领域驱动设计&#xff09;中的限界上下文划分 • 业务功能正交性评估&#xff08;高内聚、低耦合&#xff09; 技术架构拆分策略 • 数据层拆分&#xff08;垂直分库 vs 水平分表&#xff09; • 服务粒…