当前位置: 首页 > news >正文

C++的入门基础(二)

目录

  • 引用的概念和定义
  • 引用的特性
  • 引用的使用
  • const引用
  • 指针和引用的关系
  • 引用的实际作用
  • inline
  • nullptr

引用的概念和定义

在语法上引用是给一个变量取别名,和这个变量共用同一块空间,并不会给引用开一块空间。

取别名就是一块空间有多个名字

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

int main()
{int a = 2;int& b = a;int& c = a;int& d = b;//对d取别名,d是b的别名,b是a的别名,d就是a的别名b++;cout << a << " " << endl;cout << b << " " << endl;cout << c << " " << endl;cout << d << " " << endl;// 都是3//这就说明了b、c、d都是a的别名,和a共用同一块空间return 0;
}

引用的特性

1.引用在定义时必须初始化(必须说明是谁的引用)
不说明是谁的引用会报错
2.一个变量可以有多个引用(给别名取别名)
3.引用一旦引用一个实体,再不能引用其他实体
(引用不能改变指向)
1,2点比较简单,现在对第三点说明一下

链表要改变指向要用二级指针
在这里插入图片描述

int main()
{int a = 2;int& b = a;int d = 20;b = d;//这里是赋值不是引用,b不是d的引用d++;//对d++,a和b并不改变,也说明了b不是d的引用//b本来是a的引用,并不能改变成b是d的引用,说明引用不能改变指向//后面也会介绍return 0;
}

在这里插入图片描述

引用的使用

1.引用做传参和做返回值

  • 提高效率
  • 减少拷贝
  • 引用对象改变同时被引用对象改变

比如传值调用,传一个值x,函数中a拿到的是x的一份临时拷贝,而如果用引用就减少了拷贝,提高了效率,因为a是x的别名,就是给本身取了另一个名字

引用对象改变同时被引用对象改变
x++,a也++,你的别名改变了,你本身也会改变

void f1(int& x)
{x++;
}int main()
{int a = 0;f1(a);return 0;
}

引用做返回值
1.int 做返回时返回一个数值,不是直接返回而是会生成一份临时变量再返回,临时变量具有常性,不能被改变

2.int& 做返回时生成一个它的引用,再返回它的引用,数组在堆上出函数不销毁,返回数组中的引用,出函数,改变数组中的某个值
在这里插入图片描述

const引用

注意:权限放大和缩小只存在指针和引用里面
权限不能放大,可以缩小

1.权限放大

const int a = 10;//只读不能写(修改)
int& ra = a;//可以读可以写,权限放大
//正确写法
const int& ra = a;const int a = 10;//可读不可写
int& ra = a;
//权限放大
const int& ra = a;const int a = 10;
int rd = a;
//a只读,a的值拷贝进rd中,a一个空间,rd又是一个空间
//rd可读可写,这只是一个拷贝,不是权限放大,
//权限放大只存在指针和引用中

2.权限缩小

int b = 20;
const int& rb = b;b++;//21,本身权限不缩小
rb++;//不能够改变,只是它的引用权限缩小了

3. 产生临时对象
临时对象具有常性

  • 表达式运算
int a = 10;
const int& rc = 30;
const int& rd = (a+30);

在这里插入图片描述

  • 函数传值返回
int fun(int& a)
{a++;return a;
}
  • 类型的隐式转换
double d = 2.32;
int i = d;
const int& ri = d;
//double类型转化为int时,会把整型部分放入临时变量中

指针和引用的关系

指针和引用互相不可替代

  • 引用取别名不开空间,指针存一个变量的地址要开空间
  • 引用必须初始化,指针建议初始化,但是语法上不是必须的,指针可以先定义,后面把一个变量的地址放入指针中
  • 引用只能引用一个对象,而不能再引用其他对象,而指针可以不断改变指向
  • 引用可以直接访问指向对象,指针必须解引用才能访问指向对象
  • 引用和指针的sizeof含义不同,引用sizeof是引用类型的大小,指针32位平台下是4个byte,64位平台下是8个byte
  • 引用不容易出现空引用和野引用,指针容易出现空指针和野指针

野引用

int& func()
{int a = 0;return a;//会产生一个别名,返回它的一个别名//出函数别名销毁,它的引用销毁//再去找它的引用,就是野引用
}

在这里插入图片描述

空引用

int* ptr = NULL:
int& rb = *ptr;
//空引用可以通过编译
rb++;
return 0;
//rb++是对空引用的使用
//对空引用的使用,不会返回0,会返回一个负数,异常返回

表面上是对ptr这个空指针解引用,实际上它的汇编代码并不解引用,而是把ptr的地址放入一个寄存器中,再把寄存器中的地址给rb这个别名,引用的底层是指针
在这里插入图片描述

引用的实际作用

以前交换两个值用传地址的方式 swap(&a,&b);
现在有了引用,可以用swap(a,b);
在主函数中调用函数不用取地址,传参过去的函数定义用引用接收void swap(int& x,int& y),可以不用指针接收,而且不用解引用那么麻烦

但是链表中的二级指针LTNode*& != LTNode&&,指针不能用引用替代掉,C++的引用不能替代指针,因为引用不能改变指针的指向,链表要改变指针的指向用二级指针,LTNode*& == LTNode** ,引用的底层可以理解为指针

引用的实际作用体现在传参里面
使用函数模板,T可以是任意类型

template<class T>
void func(const T& val)
{//...const 对象常量->具有常性临时变量->具有常性普通变量->可以权限缩小
}

inline

用inline修饰的函数叫内联函数,C++在调用的地方直接展开内联函数,就不需要建立栈桢了,这样可以提高效率

  • C++的inline为了替代C语言的宏函数而设计出来的,宏函数也不建立栈桢,#define 定义的宏函数是一个宏,直接展开
  • 你的代码过大,不会帮你展开,比如递归层次太深,会造成可执行程序变大,内存占用变大,编译器会帮你展开代码短小重复的代码,比如swap交换两个数的值的代码
  • inline不建议声明和定义分离到两个文件,分离会导致链接错误,因为inline展开,函数定义文件的地址会消失,导致找不到函数定义,只有声明,所以定义和声明应该在同一个文件,在调用的地方展开会直接执行
  • vs下默认不展开内联函数,找到项目属性做以下设置
    在这里插入图片描述
    在这里插入图片描述
//内联函数
inline int Add(int x,int y)
{int ret = x + y;return ret;
}

未展开内联函数
call跳转地址,建立栈桢
在这里插入图片描述
展开内联函数
不跳转,直接在调用的地方展开函数逻辑
在这里插入图片描述

nullptr

nullptr是关键字
nullptr是C++中的空指针,专门用来表示空指针,nullptr只能隐式类型的转换成其他类型的指针形式不能转化成其他类型,比如int

C语言中的 ((void*)0)可以隐式类型转为int和int或其他类型,C++用这套在传参中也是不确定的,会传整型又会传指针
C++的NULL是0,传参中,一个函数的参数是int,另一个函数的参数是int
,那么会执行第一个函数,C++中的NULL指针类型又是整型0,这样比较模糊,所以空指针用nullptr表示,nullptr也是0,但它只有指针形式

void func(int* a)
{}//1
void func(int a)
{}//2
int main()
{func(0);//2func(NULL);//2func((void*)0);//会隐式类型转化,int或int*,不确定走哪个//这样说C++走不了空指针了,所以定义一个nullptr表式空指针return 0;
}
#define NULL 0  C++
#define NULL ((void*)0) C

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • vue 画二维码及长按保存
  • 基于TCP的在线词典系统(分阶段实现)(阻塞io和多路io复用(select)实现)
  • 【Linux】 GCC/G++与Makefile使用
  • Android Spinner
  • 数据结构和算法(0-1)----递归
  • ArduPilot开源代码之OpticalFlow_backend
  • arm64架构下源码编译安装kafka —— 筑梦之路
  • 【C++】———— 继承
  • 【Linux网络】IO模型{再识 IO/IO模型/阻塞IO vs 非阻塞IO/同步IO vs 异步IO}
  • LangChain内置函数全解析:深入探索与高效应用
  • iPhone 16 Pro系列将标配潜望镜头:已开始生产,支持5倍变焦
  • druid(德鲁伊)数据线程池连接MySQL数据库
  • 【ElasticSearch】ES 5.6.15 向量插件支持
  • 软件供应链安全:如何防范潜在的攻击?
  • 机器学习筑基篇,Jupyter Notebook 精简指南
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • CEF与代理
  • Java反射-动态类加载和重新加载
  • java概述
  • Java面向对象及其三大特征
  • LeetCode18.四数之和 JavaScript
  • mongo索引构建
  • MySQL-事务管理(基础)
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Xmanager 远程桌面 CentOS 7
  • 不上全站https的网站你们就等着被恶心死吧
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 基于web的全景—— Pannellum小试
  • 面试总结JavaScript篇
  • 使用 Docker 部署 Spring Boot项目
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 线性表及其算法(java实现)
  • 新手搭建网站的主要流程
  • 终端用户监控:真实用户监控还是模拟监控?
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​Redis 实现计数器和限速器的
  • !!java web学习笔记(一到五)
  • #QT(TCP网络编程-服务端)
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • ${ }的特别功能
  • (1)(1.13) SiK无线电高级配置(五)
  • (2015)JS ES6 必知的十个 特性
  • (k8s中)docker netty OOM问题记录
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (算法)硬币问题
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)树状数组
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .Net core 6.0 升8.0