003 C++基础篇

2023-11-16

前言

大家好,本文将会向您介绍引用(定义、使用场景、引用与值分别作为返回值和参数时的性能比较、引用的权限)

引用

一、引用是什么

引用:定义一个变量的别名,不是新定义一个变量,而是给已经存在的变量取了一个别名,编译器不会为引用变量单独开辟一个内存空间,它和引用的变量共用同一块内存空间

我们使用以下方式定义变量的别名
类型& 引用变量名(对象名) = 引用实体

#include <iostream>
using namespace std;
int main()
{
	int a = 1;
	int& b = a;
	cout << &a << endl;
	cout << &b << endl;
	return 0;
}

我们可以观察到变量a与它引用的变量所属的是同一块空间
在这里插入图片描述
一个变量可以有多个引用(b、c、d)

void Test()
{
       int a = 0;
       int& b = a;
       int& c = a;
       int& d = a;
       cout << &a << endl;
       cout << &b << endl;
       cout << &c << endl;
       cout << &d << endl;
}

在这里插入图片描述

二 、引用的使用场景

1、引用作参数

void swap(int& x1, int& y1)
{
    int tmp = x1;
    x1 = y1;
    y1 = tmp;
}
int main()
{
    int x = 0, y = 1;
    swap(x, y);
    cout << x <<" " << y << endl;
    return 0;
}

根据引用的特性——可知变量x,y与他们的别名是共用同一块空间的,因此对x1,y1的修改可以影响到实参x,y

在这里插入图片描述

2、引用作返回值

//定义一个结构体
struct SeqList
{
       int a[10];
       int size;
       int capacity;
};
//出了函数作用域结构体PS、a[i]都还在
int& SeqListRef(struct SeqList& ps, int i)
{
       assert(i < ps.size);
       return ps.a[i];              //返回数组第i个整型的别名
}
int main()
{
       struct SeqList s;
       s.size = 3;
       //修改返回对象(别名)
      SeqListRef(s, 0) = 10;
      SeqListRef(s, 1) = 20;
      SeqListRef(s, 2) = 30;
       //打印别名
       cout << SeqListRef(s, 0) << endl;
       cout << SeqListRef(s, 1) << endl;
       cout << SeqListRef(s, 2) << endl;
}

在这里插入图片描述
在以上场景中需要注意如果函数返回时,出了作用域,如果返回对象还在,则可以引用返回,如果已经返回给系统后则必须使用传值返回
什么意思呢?我们可以看一个程序

int& Add(int a, int b)
{
       int c = a + b;
       return c;
}
int main()
{
       int& ret = Add(1, 2);  //Add这个函数的返回值的别名为ret
       //Add(3, 4);
       cout << "Add(1,2) is :" << ret << endl;
}

上述程序是引用作返回值的场景,可是得到的结果是随机值
在这里插入图片描述
原因是:返回了一个局部变量的引用,ret引用的是已经销毁的变量c的地址,打印ret的值会导致未定义的行为,表现为打印随机值

关于引用还应注意:
引用在定义时必须初始化
引用在初始化时引用一个实体后,就不能再引用其他实体(即一旦一个实体被赋值给一个引用,那么该引用就只能指向该实体,不能再指向其他实体)
引用与实体的类型必须一致

值和引用作为函数参数的性能比较

struct A
{
    int arr[10000] = {};
};
void TestFunc1(A a)
{
    ;
}
void TestFunc2(A& a)
{
    ;
}
void parameRefAndValue()
{
    A a;
    // 以值作为函数参数
    size_t begin1 = clock();   //计时开始
    for (size_t i = 0; i < 10000; ++i)
    {
        TestFunc1(a);
    }
    size_t end1 = clock();     //计时结束
    // 以引用作为函数参数
    size_t begin2 = clock();   //计时开始       
    for (size_t i = 0; i < 10000; ++i)
    {
        TestFunc2(a);
    }
    size_t end2 = clock();     //计时结束
    // 分别计算两个函数运行结束后的时间
    cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
    cout << "TestFunc2(A&amp;)-time:" << end2 - begin2 << endl;
}
int main()
{
    parameRefAndValue();
    return 0;
}


值和引用作为返回值时的性能比较

struct A
{
       int arr[10000] = {};
};
A a;
//返回值
A TestFunc1()
{
       return a;
}
//返回引用
A& TestFunc2()
{
       return a; //返回类型为A&
}
void ReturnRefAndValue()
{
       A a;
       size_t begin1 = clock();   //计时开始
       for (size_t i = 0; i < 10000; ++i)
       {
              TestFunc1();
       }
       size_t end1 = clock();     //计时结束
       size_t begin2 = clock();   //计时开始       
       for (size_t i = 0; i < 10000; ++i)
       {
              TestFunc2();
       }
       size_t end2 = clock();     //计时结束
       // 分别计算两个函数运行结束后的时间
       cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
       cout << "TestFunc2(A&amp;)-time:" << end2 - begin2 << endl;
}
int main()
{
       ReturnRefAndValue();
       return 0;
}

在这里插入图片描述
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常底下的,尤其是当参数或者返回值类型非常大的时,效率就更低

三、引用权限

在引用过程中

权限可以平移

权限可以缩小

权限不能放大
关于权限的相关场景可以看看以下程序

int func()
{
       int a = 0;
       return a;
}
int main()
{
       const int a = 0;
       //1、权限放大
       //error:int& b = a;
       
       //2、非权限放大而是赋值,引用、指针存在权限
       // int b = a;
       
       //3、权限平移
       const int& c = a;
       
       //4、权限缩小
       int x = 0;
       const int& y = x;
       
       //5、当发生类型转换时,会产生一个带有常性的临时变量
       int i = 0; 
       //先将i给临时变量
       //常量是不具有别名的,常量在编译时就被确定了
       //error:double& d = i;
       const double& d = i;
       
       //6.返回一个局部变量
       //出了函数作用域,变量销毁,此时会将值传给一个带有常性的临时变量
       //error:int& ret = func();
       const int& ret = func();
       return 0;
}

小结

本文介绍了引用的相关知识,如果本文存在疏漏或错误的地方,还请您指出,祝您天天开心啦!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

003 C++基础篇 的相关文章

  • 我可以声明一个可以将指向自身的指针作为参数的函数吗?

    在阅读 stackoverflow 中的一个问题时 我想知道是否可以声明一个带有指向自身的指针的函数 IE 作出这样的声明foo 对于其中以下内容是正确的 foo foo 最简单的想法是转换为另一个函数指针 不能转换为void 因为它可能更
  • 用于在 n LSBits 之后清除 m 位的掩码

    我在一次采访中被问到这个问题 要清除 16 位整数的 n 位之后的 m 位 假设数字是 10010010010100101 清除 LSBit 中 5 位后的三位 之前 1001100111011001 之后 1001100100011001
  • C#/Linq 获取相邻的集合

    我有一个有序列表 例如 0 1 2 6 7 10 我想要得到数字加 1 的集合 我想要第一个数字和计数或系列 所以我会得到开始 0 计数 3开始 6 计数 2开始 10 计数 1 我怎样才能在 C 中做到这一点 答案是我认为最好的方式 对我
  • 运行WPF应用程序时出错

    该应用程序在制作它的计算机上运行良好 但是当我将其复制到另一台相同的操作系统时 它崩溃并显示以下错误 Problem signature Problem Event Name CLR20r3 Problem Signature 01 vpn
  • 从 gdb 设置 std::string 变量值?

    是否有可能 当调试器在断点处停止时 修改 std string 变量的值 而不需要采取诸如调整当前缓冲区的内存映像之类的黑客手段 例如类似于 set var mystring hello world 试试这个 经过测试并且对我有用 call
  • 如何在Windows窗体中平滑地重新绘制Panel

    如何将面板重漆成光滑的 我正在使用一个使面板无效的计时器 panel1 Invalidate 每 300 毫秒一次 然后panel1 Paint如果我向该面板添加图像 问题是它看起来像是在跳跃 我需要尽可能快地移动其上的一张图像 这是截屏问
  • 如何访问UPnP设备的服务?

    设备 贝尔金 WeMo Switch开发环境 Windows 7 上的 MS VC 2010 我正在尝试使用 Windows 中的 C 枚举 UPnP 设备的服务 我有IUPnPDevice指针并可以访问多个属性 我有IUPnPServic
  • 如何确定一个值是否在某个范围内?

    我对 C 语言比较陌生 不幸的是我必须在学校做这件事 而且我在最简单的练习中遇到了问题 这里我必须检查一个数字是否在某个区间内 例如4到6之间 我是这样制作的 include
  • 按文件创建日期排序(并枚举)目录列表?

    所以我有这个例程 public static IEnumerable
  • 如何从 .resx 文件条目获取注释

    资源文件中的字符串有名称 值和注释 The ResXResourceReader类让我可以访问名称和值 有办法看评论吗 你应该能够得到Comment via ResXDataNode class http msdn microsoft co
  • 强名称验证失败

    两台机器 均带有 NET 3 5 和 VS 2008 VC SP1 可再发行组件 单个 exe 使用两个签名的 DLL 一个在 C CLI 中 一个在 C 中 该exe在一台机器上加载并运行良好 另一方面 我在 C 可执行文件上收到 强名称
  • Unity C# 嵌套 IEnumerator

    在我的代码中 我嵌套了 IEnumerator 方法 如下所示 private IEnumerator PerformRequest string url Doing stuff UnityWebRequest request UnityW
  • 类型或命名空间名称“X”在命名空间“Y”中不存在 - 在 VS 生成的代码中

    这是我遇到过的最奇怪的错误 这个 MVC Web 项目直到今天都运行良好 几周以来还没有任何人对其进行处理 尽管没有任何改变 但现在简单地运行它会导致 命名空间 CMSModels ViewModels 中不存在类型或命名空间名称 Colo
  • Boost MPL 生成对象序列化代码?

    我想生成序列化 反序列化代码 class Object string a int b long c char d 通过查看 mpl 序列 但我需要能够识别对象并将其检索回来 我不知道如何获取它的成员的名称 我必须知道吗 代码应该看起来像 v
  • 如何使用 Sitecore Glass Mapper 渲染带有 css 类的链接

    我有以下链接 a class btn btn primary href View details a 如何使用 sitecore glass 渲染链接并使其仍然保留 css 类 使用 sitecore 中的字段渲染器 您过去可以将类作为附加
  • 在 C# 中使用 Nsubstitute 模拟具有固定参数的可选参数的函数返回 null

    我一直在尝试模拟一个包含带有固定参数的可选参数的函数 但每次我得到一个空值 这是我在接口中定义的函数 我想模拟它 List GetEntitiesByIDs List
  • 处理多个自动重定向的正确方法是什么?

    我有一个网站 基本上允许客户构建一个包含可配置项目的购物车 用户将选择一个项目 系统会提示他们选择他们想要的第一个选项 然后他们将被发送到第二个步骤 在那里他们选择第二个选项 等等 步骤数和选项数是可变的 因为它们是由客户定义的 通常该项目
  • 隐式构造函数和默认构造函数有什么区别?

    这是非常微不足道的 但是捷克语 我的母语 不区分隐式和默认 所以我对一些捷克语翻译感到困惑 隐式和默认构造函数或构造函数调用之间有什么区别 struct Test Test int n 0 您能用这些术语描述以下语句的作用吗 Test t1
  • 将 CreateThread 与 lambda 结合使用

    只是试验 但我想知道是否可以使该代码工作 如编译 void main int number 5 DWORD dontThreadOnMe PVOID PVOID data int value int data cout lt lt valu
  • 删除重复项并将列表放入列表框中

    这是一项大学作业 我对其中的一部分遇到了问题 这是代码 namespace Assignment 1 public partial class Classifier System Web UI Page We are using a web

随机推荐

  • getClassLoader()返回null,getClassLoader()获取为空

    一 问题描述 通过getClassLoader 的方式获取jar包中的资源 为空 this getClassLoader getResources com xxxx test Start class hasMoreElements this
  • gin context和官方context_go-gin框架入门

    gin入门 介绍 gin是一个golang的微框架 封装比较优雅 api友好 源码注释比较明确 具有快速灵活 容错方便等特点 对于golang而言 web框架的依赖要比python java之类的要小的多 完全使用自身net http包封装
  • 课时 10 自测题

    使用存储快照功能需要用到哪些 Kubernetes API 资源对象 多选题 A VolumeSnapshot B VolumeSnapshotClass C VolumeSnapshotContent D PersistentVolume
  • C++学习 十、函数重载,函数模板

    C 学习 十 函数重载 函数模板 前言 函数重载 二义性 强制类型转换 类型与类型引用 默认参数 const指针参数和const引用参数 函数模板 模板函数声明与定义 函数模板重载 显式实例化 显式具体化 重载解析 引导编译器使用函数模板
  • Box layout

    Layout management with layout classes is much more flexible and practical It is the preferred way to place widgets on a
  • Vue3+TypeScript 完整项目上手教程

    转自 Vue3拥抱TypeScript的正确姿势 https juejin im post 6875713523968802829 一个完整的Vue3 Ts项目 支持 vue和 tsx写法 项目地址 https github com vin
  • Tomcat的安装与环境变量配置(图文详解)

    Tomcat的安装与环境变量配置 首先说明一下我的电脑配置 Windows 7 专业版 64位操作系统 安装内存8G 四核处理器 一 Tomcat的下载与安装 1 进入Tomcat官网 https tomcat apache org 2 在
  • soap错误码和获取处理错误码的详细信息

    gsoap页面 https www genivia com doc guide html index html soap客户端用户登录返回值错误代码表 ERROR CODE SOAP EOF 1 Unexpected end of file
  • const 在C和C++ 中的区别

    目录 c中的const C 中的const const修饰指针 const修饰引用 const是construct的缩写 是c c 语言中的类型限定符 采用const修饰变量 功能是对变量声明为只读特性 并保护变量值以防被修改 c中的con
  • 最新版Adobe2023:After Effects 2023(Ae2023) win/mac版中文特别版

    Adobe After Effects 2023 AE2023 它用于视频处理后期制作 创建音乐视频 广告 动画 标题以及许多其他需要数字视频效果的元素 Adobe After Effects提供了出色的控制功能 广泛的创意工具以及与其他视
  • 香港云服务器怎么样_硅云服务器评测

    这次我来给大家测试下香港云服务器 本次测试选用的硅云香港可用一区 使用到的配置是2H2G 官方文档介绍说通用型g1是50 cpu性能 因为想用Linux 只是做下简单评测 就选择了通用型 正式使用的朋友建议买标准型S 100 CPU性能 一
  • android studio gradle 下载失败万能解决方案

    The specified Gradle distribution https services gradle org distributions gradle 7 2 2 bin zip does not exist 报错如上 介绍个绝对
  • 飞腾平台 银河麒麟 安装nginx

    飞腾平台 银河麒麟 安装nginx 1 在 home目录输入命令新建npf文件夹 mkdir npf 进入npf 目录输入命令新建nginx server文件夹 mkdir nginx server 2 将以下安装包上传到nginx ser
  • U-boot在S3C2440上的移植详解(一)

    本文转载至 http www embeddedlinux org cn html jishuzixun 201303 16 2499 html 一 移植环境 主 机 VMWare Fedora 9 开发板 Mini2440 64MB Nan
  • 小程序开发之 wx.getUserInfo获取用户信息方案介绍

    原文链接 https www cnblogs com kenshinobiy p 9118024 html 背景 小程序一个比较重要的能力就是获取用户信息 也就是使用 wx getUserInfo 接口 我们发现几乎所有的小程序都会调用这个
  • websocket有什么特点

    websocket有什么特点 答 websocket的最大特点就是 服务器可以主动向客户端推送信息 客户端也可以主动向服务器发送信息 是真正的双向平等对话 属于服务器推送技术的一种 1 建立在tcp协议之上 服务器端的实现比较容易 2 与H
  • 多线程处理

    https www runoob com python3 python3 multithreading html import requests import threading import time import xlrd import
  • 二维数组分组,一行显示5个,适合在table里面显示,php控制显示的数据

    需求 把数据平均显示到table的显示框内 如一行5个数据 效果 方法代码 一行展示N个数据 param int type 默认1 可扩展 param int num 一行显示的个数 可设置 param arrs 二维数组 static f
  • 强化学习学习

    强化学习一些基本概念 强化学习是除了监督学习和无监督学习的第三种机器学习方法 监督学习 Supervised Learning 是从外部监督者提供的带标注训练集中进行学习 任务驱动 无监督学习 Unsupervised Learning 是
  • 003 C++基础篇

    前言 大家好 本文将会向您介绍引用 定义 使用场景 引用与值分别作为返回值和参数时的性能比较 引用的权限 引用 一 引用是什么 引用 定义一个变量的别名 不是新定义一个变量 而是给已经存在的变量取了一个别名 编译器不会为引用变量单独开辟一个