一篇文章帶你搞懂C++引用(建議收藏)

引用

6.1 引用概念

引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間

比如:李逵,在家稱為"鐵牛",江湖上人稱"黑旋風"

typedef 是給類型取別名

引用是給變量取別名

注意:引用類型必須和引用實體是同種類型的

類型& 引用變量名(對象名) = 引用實體;

int main()
{int a = 0;//定義一個變量a,賦值為0,int &b = a;//這里的&不是取地址符,而是引用,給變量取別名, &定義在一個類型和變量之間為引用//定義一個空間為a,又給這個空間a取別名為bint a = 0;int b = a;//這種寫法和上面是完全不同的,//這里是 定義一個變量為a,a的值是0,定義一個變量為b,用a的0初始化return 0;
}

如何證明是否公用一塊空間?


#include <iostream>
using namespace std;int main()
{int a = 0;int& b = a;cout << &b << endl;//取地址cout << &a << endl;//取地址a++;b++;return 0;
}

6.2 引用的特性

1. 引用在定義時必須初始化

int main()
{int a = 1;int& b;//引用在定義時必須初始化return 0;
}

2. 一個變量可以有多個引用(可以取無限個別名)

int main()
{int a = 1;int &b = a;int &c = a;int &d = c;//還可以給別名取別名a++;return 0;
}

3. 引用一旦引用一個實體,再不能引用其他實體

指針指向一個實體后,可以改變,引用不可以改變

int main()
{int a = 1;int& b = a;int& c = a;int& d = c;int x = 10;//引用一旦擁有一個實體,再不能引用其他實體b = x;b是x的別名呢?還是x賦值為b?return 0;
}

這里把x賦值給b

6.3 常引用

權限不能放大

int main()
{int a = 13;int& b = a;//權限不能放大const int c = 20;//int& d = c;const int& d = c;//權限可以縮小,從只讀的角度int e = 25;const int& f = e;      return 0;
}

隱式類型轉換和強制類型轉換都是會產生臨時變量

所有的轉換都不是對原變量進行轉換和提升,而是之間產生臨時變量

并不會改變原變量類型,

這里本質上是權限的放大和縮小

類型轉換中間是會產生臨時變量的,臨時變量具有常性,相當于const修飾

int main()
{int ii = 1;doubble dd = ii;//int類型可以給double,會發生隱式類型轉換double& rdd = ii;//double類型的數據可以變成int的引用嗎?//不可以  這里不能引用的原因不是說類型不匹配,而是不能進行權限的放大const double& rdd = ii;//這里可以引用是因為權限的平移 中間產生的臨時變量也是相當于const修飾的變量//此時rdd引用的不是ii,而是int轉換成double之間產生的臨時變量,//這個臨時變量具有常性return 0;
}

const 可以把一個常量起一個別名

const int& x = 10;

應用場景:

如果使用引用傳參,函數內如果不改變n,那么盡量用const引用傳參

const引用傳參會有非常強的接受度

????????

6.4 引用的使用場景

1.做參數

a.輸出型參數

b.大對象傳參,提高效率

2.做返回值

a.輸出型返回對象,調用者可以修改返回對象.

b.減少拷貝提高效率,

不是什么時候都可以使用傳引用返回,要注意使用場景

出了作用域,返回對象還在可以用傳引用返回

出了作用域,返回對象銷毀.那么一定不能用引用返回,一定要用傳值返回

1. 做參數 --(引用的輸出型參數)

如果不用引用,傳入的是實參的一份臨時拷貝,形參的改變不會影響實參

如果想改變 必須使用指針 傳入地址

在C++里,這里x是a的別名,y是b的別名,x和y的交換就是a和b的交換

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 3;int b = 5;cout <<"交換前:" << a << ' ' << b << endl;Swap(a, b);cout <<"交換后:" << a << ' ' << b << endl;return 0;
}

例如:有些書里會把數據結構里鏈表部分弄得很復雜

typedef struct SListNode
{.....
}SLTNode,*PSLTNode;
//這里的*PSLTNode 相當于typedef struct SListNode* PSLTNode  給這個結構體指針起了個別名 PSLTNode
void SListPushBack(PSLTNode& phead,int x)//這里的引用相當于 phead是list的別名,phead的改變會影響list
{.....
}
int main()
{SLTNode* list = NULL;SListPushBack(list,1);SListPushBack(list,1);SListPushBack(list,1);return 0;
}

大對象傳參 提高效率

#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{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&)-time:" << end2 - begin2 << endl; 
}

2. 做返回值

傳值返回 都會生成一個返回對象拷貝作為函數調用的返回值

返回的是n嗎 是用n的拷貝來做表達式的返回值

為什么編譯器要這么做?

如果這里沒有static ,n返回時,出了該作用域 會銷毀 置為隨機值

傳引用返回:

引用返回的語法含義:返回返回對象的別名

不是什么時候都可以使用傳引用返回,要注意使用場景

返回n的別名 越界了為什么不報錯呢?

ret的結果是未定義的 如果棧幀結束時,系統清理棧幀置成隨機值,那么這里ret的結果就是隨機值

下面程序使用引用返回本質是不對的,結果是沒有保障的

int& Count()
{int n = 0;n++;// ...return n;
}
int main()
{int ret = Count();return 0;
}

如果引用ret ,那么相當于 ret也是n的別名,結果會不會有所不同

int& Count()
{int n = 0;n++;// ...return n;
}
int main()
{int& ret = Count();printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);return 0;
}

總結:出了函數作用域,返回對象就銷毀了,那么一定不能用引用返回,一定要用傳值返回

什么時候可以用引用返回?

使用static

1. static修飾變量

???a. 函數中局部變量:

??????聲明周期延長:該變量不隨函數結束而結束

??????初始化:只在第一次調用該函數時進行初始化

??????記憶性:后序調用時,該變量使用前一次函數調用完成之后保存的值

??????存儲位置:不會存儲在棧上,放在數據段

int& Count()
{static int n = 0;n++;// ...return n;
}
int main()
{int& ret = Count();printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);return 0;
}
const引用

為什么這里給c取別名不可以?

本質上是權相的放大 c自己是const類型 不可以修改

用d取別名 使得d是權限的放大 可以修改

#include <iostream>using namespace std;int main()
{int a = 10;//權限的的平移int& b = a;const int c = 20;//權限的放大int& d = c;int e = 30;//權限的縮小const int&f = e;//只讀的角度變成你的別名return 0;
}

權限不可以放大,但是權限可以縮小

int main()
{int ii = 1;double dd = ii;//發生隱式類型轉換double& rdd = ii;//double不可以變成int的引用//不可以使用的本質原因是 因為權限的放大,因為 int 類型要轉換成double類型//中間要先生成一個double類型的臨時變量,相當于 const double ii;//double& dd = const double ii; //權限的放大不可以const double& rdd = ii;//可以使用權限的平移return 0;
}

強制轉換并不是改變原變量類型 他也是產生一個臨時變量

如果使用引用傳參,函數內如果不改變n,那么盡量用const引用傳參

void func1(int& n)
{}
void func2(const int& n)
{}
int main()
{int a = 10;const int b =20;func1(a);func1(b);func1(30);func2(a);func2(b);func2(30);double c = 1.11;func2(c);return 0;
}

指針和引用的差別

指針和引用用途基本是相似的

但有

1.使用場景的差別

引用和指針的不同點:

1. 引用在定義時必須初始化,指針沒有要求

2. 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何一個同類型

實體

3. 沒有NULL引用,但有NULL指針

4. 在sizeof中含義不同引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32位平臺下占

4個字節)

5. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小

6. 有多級指針,但是沒有多級引用

7. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理

8. 引用比指針使用起來相對更安全

2.語法特性以及底層原理的差別

從語法角度而言,引用沒有開辟空間,指針開了四個字節或者8個字節的空間

底層實現角度,那么引用底層是用指針實現的

個人水平不足 如果代碼中有錯誤,可以多多在評論區指出,一定會及時修改!
謝謝大家看到這里 覺得有收獲的話可以三連一下 一起加油!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/24110.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/24110.shtml
英文地址,請注明出處:http://en.pswp.cn/web/24110.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux.軟件操作

1.yum 命令 要連網 2.systemctl 命令控制軟件的啟動和關閉 3.ln 創建軟連接 使用cat來找本體&#xff0c;看看鏈接生不生效 4.date 命令查看系統時間 格式化的時候可以用雙引號把他們引出來 -d 對時間進行修改 修改時區 自動校準 手動校準 5.ifconfig 查看本機的ip地址 6.h…

mysql undolog管理

在MySQL中&#xff0c;Undo Log&#xff08;撤銷日志&#xff09;用于支持事務的回滾和MVCC&#xff08;多版本并發控制&#xff09;。為了避免Undo Log不斷增長&#xff0c;影響系統性能&#xff0c;需要進行合理的清理。MySQL的Undo Log清理策略主要依賴于系統的配置參數和后…

Ansible——get_url模塊

目錄 主要用途 參數總結 基本語法示例 使用示例 示例1&#xff1a;下載文件 示例2&#xff1a;使用校驗和驗證文件 示例3&#xff1a;使用 HTTP 基本認證 示例4&#xff1a;通過代理服務器下載文件 示例5&#xff1a;設置文件權限、所有者和組 示例6&#xff1a;強制…

5.31.15 使用圖像到圖像轉換和 YOLO 技術對先前的乳房 X 光檢查結果中的異常進行早期檢測和分類

在本研究中&#xff0c;我們研究了基于 You-Only-Look-Once (YOLO) 架構的端到端融合模型的有效性&#xff0c;該模型可同時檢測和分類數字乳房 X 光檢查中的可疑乳腺病變。包括四類病例&#xff1a;腫塊、鈣化、結構扭曲和正常&#xff0c;這些病例來自包含 413 個病例的私人數…

ic基礎|復位篇02:芯片中的“人生重來槍”!crg之復位系統

大家好&#xff0c;我是數字小熊餅干&#xff0c;一個練習時長兩年半的ic打工人。我在兩年前通過自學跨行社招加入了IC行業。現在我打算將這兩年的工作經驗和當初面試時最常問的一些問題進行總結&#xff0c;并通過匯總成文章的形式進行輸出&#xff0c;相信無論你是在職的還是…

范閑獲取到慶帝與神廟的往來信件,用AES進行破解

關注微信公眾號 數據分析螺絲釘 免費領取價值萬元的python/java/商業分析/數據結構與算法學習資料 在《慶余年2》中&#xff0c;范閑與慶帝和神廟之間的權謀斗爭愈演愈烈。一次偶然的機會&#xff0c;范閑從慶帝的密室中獲取到幾封與神廟往來的密信。然而&#xff0c;這封信件…

eclipse連接后端mysql數據庫并且查詢

教學視頻&#xff1a;https://www.bilibili.com/video/BV1mK4y157kE/?spm_id_from333.337.search-card.all.click&vd_source26e80390f500a7ceea611e29c7bcea38本人eclipse和up主不同的地方如下&#xff0c;右鍵項目名稱->build path->configure build path->Libr…

【懸架筆記三】1/4被動懸架垂向動力學仿真+頻域特性分析

1/4被動懸架 代碼&#xff1a; %書第156頁、159頁 clc clear close all %% 一.懸架參數 ms320; mw50; Ks22000; Cs1500; Kw195000; f00.07; %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 二.垂向振動動力學仿真 %% 二.1.狀態方程 A [0 1 0 -1;.…

機器人--矩陣運算

兩個矩陣相乘的含義 P點在坐標系B中的坐標系PB&#xff0c;需要乘以B到A到變換矩陣TAB。 M點在B坐標系中的位姿MB&#xff0c;怎么計算M在A中的坐標系&#xff1f; 一個矩陣*另一個矩陣的逆矩陣

JavaSE 實戰五子棋中國象棋(單機簡易版)

介紹 JavaSE實踐五子棋和中國象棋游戲&#xff0c;棋盤&#xff0c;棋子繪制&#xff0c;輸贏判定重置棋盤&#xff0c;單機博弈。 五子棋棋盤 中國象棋棋盤 使用說明 啟動類 Main.java&#xff0c; 面板類 Panel.java繪制棋盤和玩法&#xff0c;實體類 ChessPiecesNode.jav…

適配器模式 Adapter

一種結構型設計模式&#xff0c;它允許將不兼容的對象轉換成可兼容的接口。主要目的是解決在不改變現有代碼的情況下&#xff0c;使不兼容的接口之間能夠正常工作&#xff0c;通過創建一個中間轉換的適配器來將一個對象轉換成我們所需要的接口。 場景&#xff1a; 當你原來的某…

【Text2SQL 論文】MAC-SQL:多個 Agents 合作來解決 Text2SQL

論文&#xff1a;MAC-SQL: A Multi-Agent Collaborative Framework for Text-to-SQL ???? arXiv:2312.11242, 北航 & Tencent Code: MAC-SQL | GitHub 文章目錄 一、論文速讀二、MAC-SQL2.1 Selector agent2.2 Decomposer agent2.3 Refiner agent 三、指令微調的 SQL-L…

2024.06.07【讀書筆記】丨生物信息學與功能基因組學(第十一章 分子水平的系統發生和進化 第四部分)【AI測試版】

讀書筆記四&#xff1a;《生物信息學與功能基因組學》第十一章第四部分 分子系統發生的專用名詞與樹的拓撲結構 在《生物信息學與功能基因組學》第十一章的第四部分&#xff0c;作者介紹了分子系統發生分析中的專用名詞&#xff0c;并詳細解釋了系統發生樹的拓撲結構和分支長…

【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕獲組和 + 的含義

目錄 問題解決方案討論 問題 本文討論一些按照特定的文本模式進行的查找和匹配。 解決方案 如果想要匹配的只是簡單文字&#xff0c;通常我們使用一些內置的基本字符串方法即可&#xff0c;如&#xff1a;str.find()&#xff0c;str.startwith()&#xff0c;str.endswith() …

Day49 動態規劃part08

LC139單詞拆分(未掌握) 未掌握分析&#xff1a;將字符串s中的各個字符看成是背包&#xff0c;思考成了多重背包問題單詞就是物品&#xff0c;字符串s就是背包&#xff0c;單詞能否組成字符串s&#xff0c;就是問物品能不能把背包裝滿。拆分時可以重復使用字典中的單詞&#xf…

轉速傳感器介紹

一、概述 RPM&#xff08;Revolutions Per Minute&#xff09;轉速傳感器是一種用于測量旋轉機械設備轉速的傳感器。它可以檢測旋轉部件上的特定位置標記&#xff08;如齒輪、凸起或磁鐵&#xff09;&#xff0c;并根據這些標記的通過頻率來計算轉速。發電額定頻率是50hz和60z…

ubuntu18.04環境下,arduino ide在打開串口監視器時報錯

ubuntu18.04環境下&#xff0c;arduino ide在打開串口監視器時報錯 Exception in thread “AWT-EventQueue-0” java.lang.UnsatisfiedLinkError: /home/lzx/.jssc/linux/libjSSC-2.8_x86_64.so: /home/lzx/.jssc/linux/libjSSC-2.8_x86_64.so: file too short 這個錯誤表明 li…

力扣1574.刪除最短的子數組使剩余數組有序

力扣1574.刪除最短的子數組使剩余數組有序 剩下有序 –> 前面一段 后面一段 有序 前面有序 后面有序 前面最后一項 < 后面第一項先反向遍歷找到right的最小值然后正向遍歷找left的最大值當nums[left] > nums[right]時 right class Solution {public:int findLen…

java線程變量共享

在Java中&#xff0c;線程變量共享可以通過幾種方式實現&#xff1a; 1.實例變量&#xff1a;如果一個實例變量被多個線程共享&#xff0c;你需要確保適當的同步&#xff0c;以避免競態條件。你可以使用synchronized關鍵字或者Lock接口來保護共享變量。 2.靜態變量&#xff1a;…

openh264 降噪功能源碼分析

文件位置 ● openh264/codec/processing/denoise/denoise.cpp ● openh264/codec/processing/denoise/denoise_filter.cpp 代碼流程 說明&#xff1a;從代碼流程可以看到&#xff0c;實現降噪的核心功能主要就是BilateralDenoiseLuma、WaverageDenoiseChroma兩個函數。 原理…