《C++程序设计》阅读笔记【5-引用】

在这里插入图片描述

在这里插入图片描述

🌈个人主页:godspeed_lucip
🔥 系列专栏:《C++程序设计》阅读笔记

本文对应的PDF源文件请关注微信公众号程序员刘同学,回复C++程序设计获取下载链接。


  • 1 引用
    • 1.1 概念
    • 1.2 和引用相关的操作
      • 1.2.1 什么能被引用
    • 1.3 用引用传递函数参数
    • 1.4 用引用返回值
    • 1.5 const限定引用
    • 1.6 返回堆中变量的引用
  • 2 总结


1 引用

1.1 概念

引用作为目标的别名而使用,对引用的改动实际就是对目标的改动。

例如:rInt就是someInt的引用

int someInt;
int  &rInt = someInt;
//int &rInt、int& rInt、int & rInt都是等价的

引用不是值,不占存储空间,声明引用时,目标的存储状态不会改变。

引用只有声明,没有定义(定义必然设计到分配具体空间)

引用在声明时必须被初始化,则会产生编译错误。例如:int &rInt是错误的

虽然引用运算符与地址操作符使用相同的符号(&),但它们不是一样的

&除了引用之外,其他任何时候使用都表示取地址操作符。例如int i=1; cout<<&i;是输出整形变量i的地址。

1.2 和引用相关的操作

引用的地址是被引用目标的地址

引用被建立后,实际上就不能让引用指向新的引用目标,因为对引用的操作就是对其引用目标的操作。请看下面的例子:

#include<iostream>
using namespace std;int main(){int origin = 1;int & r_origin = origin; //建立对origin变量的引用cout<<&origin<<endl;cout<<&r_origin<<endl; //输出两者的地址cout<<origin<<endl;cout<<r_origin<<endl; //输出两者的值int other = 2; //新建立一个int变量r_origin = other; //试图让引用指向新的引用目标cout<<origin<<endl;cout<<r_origin<<endl;cout<<other<<endl;//输出三者的值exit(0);
}

结果:

image-20240229135316766

从上面这个例子也可以看出引用和指针的差别:

引用不能改变指向,但是指针是可以改变指向的(指针常量除外)

1.2.1 什么能被引用

  1. 若一个引用对象被声明为Type &r = value,则要求valueType类型,或者value可以被隐式转换为Type类型。

有待商榷,我的C++03版本的dev中,下面的代码是错误的:

int main(){int a = 1;double &b = a;return 0;
}
  1. 如果引用类型Type的初始值不是一个左值,那么将建立一个Type类型的目标并用初始值初始化,那个目标的地址变成引用的值。

事实上我感觉这条有待商榷。我的C++版本是C++03。下列代码都是错误的:

void test02() {double& r_dou_1 = 1;double& r_dou_2 = 1.0;
}

只有这样才是正确的:

void test02() {double sour = 1.0;double& r_dou_2 = sour;
}
  1. 指针也是一种数据类型,也可以被引用。例如:
void test03(){int b=1;int* a = &b;int* &point_r = a;cout<<*point_r<<endl;
}

结果:

image-20240229143646930

TIP:
int* a = &1;是错误的,只能像int b=1; int* a = &b;才可以。

因为1是一个常量右值,它没有一个明确的内存地址

  1. 不可以对void进行引用。例如
void& a=3; //error

void只是在语法上相当于一个类型,本质上不是类型,没有任何一个变量或对象的其类型为void

  1. 数组不能被引用

一方面,数组是某个数据类型元素的集合,每个元素皆为引用,意味着每个元素必须初始化为其他内存实体;并且数组的大小必须在编译时就确定,但是引用是在运行时才进行绑定的,因此引用的数组是错误的;

另一方面,数组名只是表示该元素集合空间的起始地址,若对其引用,那就是数组的别名,与指向数组的指针没有什么区别

其实好像也是可以引用的,例如:

int main(){int arr[] = {1, 2, 3, 4, 5};int (&ref)[5] = arr; // 引用数组cout<<ref<<endl;return 0;
}

其结果就是:

image-20240321124812610

  1. 不可以对引用再次引用,也不可以用指针指向引用

其实很好理解,引用本质上不是对象,不占用内存空间。被引用和指向的目标都必须是一个对象。

  1. 引用不可以使用类型来初始化

例如:

int &ra = int; //error

理解:引用是变量或者对象的引用,而不是类型的引用

  1. 空引用不能存在,如:int &r = NULL是错误的

1.3 用引用传递函数参数

因为引用就是变量的别名,传递引用就是在传递引用对象本身。

传递引用给函数与传递指针的效果一样,传递的是原来的变量或对象(事实上,在底层还是通过传递地址的方式实现的),而不是在函数作用域内建立变量或对象的副本。

例子:使用引用交换变量值

void swap(int &x,int &y){int temp = x;x = y;y = temp;
}void run_swap(){int a=0;int b=4;cout<<a<<endl;cout<<b<<endl;swap(a,b);cout<<a<<endl;cout<<b<<endl;
}int main(){run_swap();
}

结果:

image-20240229151853914

注意:下面的两个重载函数会报错:

image-20240229152116576

1.4 用引用返回值

请看以下例子:

image-20240229152917992

对于第一种情况:

fn1以值的形式返回。在返回全局变量temp时,编译器会在fn1函数的栈空间中,创建临时变量存储temp的值。之后再将该临时变量赋值给a

对于第二种情况:

fn1以值的形式返回。与第一种情况相同,编译器同样会创建临时变量。但是接受该变量的是一个引用,于是引用b的引用变量就变成了该临时变量。但是,由于临时变量是存储在fn1的栈空间中的,但是当fn1返回后,其数据就会被销毁,所以引用b就会指向一个无意义的数据。因此会出现warning。正确做法是这样的:

int  x = fn1(5.0);
int &b = x;

对于第三种情况:

fn2以引用的形式返回,因此不会创建数据副本,而是直接把c赋值为全局变量temp的值。

对于第四种情况:

以引用的形式返回,同时以引用的形式接受。这时候,引用d的目标对象就是temp

返回局部变量的引用是错误的(类似于返回局部变量的指针)。因为这可能导致对已释放内存的引用或失效的对象的引用,进而引发未定义行为。

1.5 const限定引用

简单来说,加上const之后,引用就只能被读,不能被修改

例如下面的代码:
image-20240229161955603

其结果为:(代码较简单,不详细解释)
image-20240229162013013

1.6 返回堆中变量的引用

小tip:

正确代码:

int *p =  new int(20);
int* &ref = p;

错误代码:

int* &ref = new int(20);

解释:原因是 new int(20) 返回的是一个右值(rvalue),而非左值(lvalue)。在C++中,非const引用无法绑定到右值,因为右值通常是临时的,不可修改。

考虑到new不一定能成功申请到内存,所以可能返回NULL,但是引用不可以是NULL。所以最好增加一个检查

释放内存:

在上述的例子中,ref是指针p的引用,因此可以使用delete refdelete p释放。

当然,假如代码是这样的:

int *p =  new int(20);
int &ref = *p;

那么,使用delete &ref(注意这里的&是取地址操作)或者delete p释放。

2 总结

C++,犹如编程的交响乐, 在代码的海洋中奏响和谐的旋律。

它是创造者的笔,雕刻着无尽可能,

是思想的翅膀,让梦想飞翔的天空。

无拘无束,灵活多变。

C++,是程序员心中的宝藏,永不凋零的花朵。

渴望挑战C++的学习路径和掌握进阶技术?不妨点击下方链接,一同探讨更多C++的奇迹吧。我们推出了引领趋势的💻C++专栏:《C++程序设计》阅读笔记,旨在深度探索C++的实际应用和创新。🌐🔍

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

WebKit结构揭秘:探秘网页渲染的魔法之源

一、WebKit之心&#xff1a;渲染引擎的魔力 WebKit的渲染引擎是其核心所在&#xff0c;它犹如一位技艺高超的魔法师&#xff0c;将HTML、CSS和JavaScript的魔法咒语转化为绚丽的网页画面。它解析代码&#xff0c;绘制页面&#xff0c;让网页内容跃然屏上&#xff0c;展现出无尽…

openpyxl的使用

1、中文手册 openpyxl-一个Python库&#xff0c;用于读/写excel2010 xlsx/xlsm文件 — openpyxl 3.0.5 文档

单片机学习day1(点亮流水灯)

1. 位运算 &:按位与 &#xff08;与0得0、与1不变&#xff09;&#xff08;全1为1&#xff0c;有0得0&#xff09;指定位置1 |:按位或 &#xff08;或1得1、或0不变&#xff09;&#xff08;全0为0&#xff0c;有1得1&#xff09;指定位置0 ^:按位异…

ROS 2边学边练(15)-- 写一个简单的服务(C++)

前言 此篇我们即将编写一个简单的服务&#xff08;service&#xff09;通信例子&#xff0c;客户端节点向服务端节点发出请求&#xff08;.srv文件中规定了通信的数据结构格式&#xff09;&#xff0c;服务端节点收到请求后将结果回复给客户端节点&#xff0c;一问一答&#xf…

力扣-简化路径

题目 71简化路径 思路 这个题和逆波兰表达式求值很想&#xff0c;都是通过使用栈来实现。 对于给定的绝对路径&#xff0c;首先可以使用 “/” 将其分割&#xff0c;分割后的字符串共包括四种情况&#xff1a; 空字符串&#xff08;例如当绝对路径为"//"时&#x…

Unity类银河恶魔城学习记录12-4 p126 Item Tooltip源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI.cs using System.Collections; using System.Collections.Generic; usi…

【面经】interrupt()、interrupted()和isInterrupted()的区别与使用

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;面经 ⛺️稳中求进&#xff0c;晒太阳 interrupt方法 如果打断线程正在sleep&#xff0c;wait&#xff0c;join会导致被打断的线程抛出InterruptedException&#xff0c;并清除打断标记。如…

Redis的配置文件详解

单位&#xff1a;Redis配置对大小写不敏感&#xff01; 注意这里&#xff1a;任何写法都可&#xff0c;不区分大小写。 units are case insensitive so 1GB 1Gb 1gB are all the same.包含&#xff1a;搭建Redis集群时&#xff0c;可以使用includes包含其他配置文件网络&…

PyTorch之Torch Script的简单使用

一、参考资料 TorchScript 简介 Torch Script Loading a TorchScript Model in C TorchScript 解读&#xff08;一&#xff09;&#xff1a;初识 TorchScript libtorch教程&#xff08;一&#xff09;开发环境搭建&#xff1a;VSlibtorch和Qtlibtorch 二、Torch Script模型格…

关于 elf loader 的编写

可以使用如下命令观看 elf 文件的信息 readelf -a build/ramdisk.img | vim -在编写 elf loader 的时候&#xff0c;实际上只有下图这一部分 “Program Headers” 是有用的 凡是类型为 “LOAD” 的就是需要加载进内存的部分 所以&#xff0c;只要把这些部分加载进内存里&…

数据库不用mmap

你确定你想用 MMAP 实现数据库么&#xff1f;_哔哩哔哩_bilibili MMAP 的随机读与顺序读的性能表现不好&#xff0c;以及对于写主要是不可控的刷入时机以及代码冗余&#xff0c;所以 MMAP 不适合在数据库中使用。 mmap是posix系统调用&#xff0c;它提供由操作系统管理内存映…

acwing算法提高之图论--最小生成树的典型应用

目录 1 介绍2 训练 1 介绍 本专题用来记录使用prim算法或kruskal算法求解的题目。 2 训练 题目1&#xff1a;1140最短网络 C代码如下&#xff0c; #include <iostream> #include <cstring>using namespace std;const int N 110, INF 0x3f3f3f3f; int g[N][N…

(C)1008 数组元素循环右移问题

1008 数组元素循环右移问题&#xff1a; 问题描述 输入样例&#xff1a; 6 2 1 2 3 4 5 6 输出样例&#xff1a; 5 6 1 2 3 4 解决方案&#xff1a; #include<stdio.h> #include<string.h> #include<math.h> int main(){int n,k,flag,y,x,final;int a[10000…

Flutter Boost 3

社区的 issue 没有收敛的趋势。 设计过于复杂&#xff0c;概念太多。这让一个新手看 FlutterBoost 的代码很吃力。 这些问题促使我们重新梳理设计&#xff0c;为了彻底解决这些顽固的问题&#xff0c;我们做一次大升级&#xff0c;我们把这次升级命名为 FlutterBoost 3.0&am…

合理早餐选择,稳定糖尿病血糖。

对于糖尿病患者来说&#xff0c;饮食管理是治疗的重要一环。不合理的早餐选择会导致血糖的波动。很多糖尿病朋友按时吃药&#xff0c;但是血糖就是稳定不住&#xff0c;之前看过一个例子&#xff0c;北京崇文门医院朱学敏主任接诊过一个患者&#xff0c;那个患者按时吃药&#…

LaTeX 空格与换行

任意多个空格与一个空格的功能相同。只有字符后面的空格是有效的&#xff0c;每行最前面的空格被忽略。单个换行被视作一个空格&#xff0c;连续两个换行表示分段。~被称作一种不可打断的空格&#xff0c;排版系统不会在这种空格之间换行。西文的逗号、句号和分号等标点后面应该…

Java | Leetcode Java题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; class Solution {public int myAtoi(String str) {Automaton automaton new Automaton();int length str.length();for (int i 0; i < length; i) {automaton.get(str.charAt(i));}return (int) (automaton.sign * automaton.ans);} …

Android Studio学习10——资源res的使用

一、String,StringArray的使用 一次修改&#xff0c;多出生效 String StringArray 二、color的使用 颜色代码对应表 和上面的相似用法 三、Dimen(尺寸)的使用 用的少&#xff0c;一般直接写尺寸 四、如何写一个drawable作为背景 五、如何写一个可以改变的drawable(按钮按下…

IP地址:是给主机配置的,还是给网卡配置的?

在探索网络的奥秘时&#xff0c;我们经常会遇到一个看似简单但又复杂的问题&#xff1a;IP地址到底是配置在主机上&#xff0c;还是配置在网卡上&#xff1f;为什么我们通常说的是“主机IP地址”呢&#xff1f;让我们一起深入探讨。 1. 网卡与IP地址 &#x1f5a5;️&#x1f…

利用OllyDbg对程序内容进行修改实验

1.双击运行exe文件&#xff0c;出现如下弹窗 2.用ollydbg工具打开该执行文件&#xff0c;页面显示如下 3.在注释窗口执行以下操作 4.双击运行exe文件时&#xff0c;显示”Copied!”所以接下来在注释里找到这个字样&#xff0c;如下&#xff0c;我们需要把对话框中的内容修改为“…