想和高手侃侃而谈C++引用?看这一篇就够了【C++引用】
- 定義
- 應用
- 存在對指針取引用
- 不存在對引用取地址
- 存在指針的指針,不存在引用的引用
- 存在指針數組,不存在引用數組
- 數組的引用
- 常引用
- 常引用的特性
- 臨時對象的常引用
- 類型不同的變量常引用本質剖析
- 在能夠使用 const 的地方就使用 cosnt
- 引用的本質
- 引用的大小
- 引用的類型
- 結論
- 反匯編比對指針和引用
- 源代碼
- 匯編代碼比對結果
- 結論
定義
變量名本身是一段內存的引用,也就是別名。
引用是為已有變量起別名。
引用是聲明關系,不分配內存空間(宏觀)。
引用必須初始化,不能獨立存在。
與被別名的變量具有相同數據類型。
代碼演示:
#include <iostream>using namespace std;int main() {int a = 100;int& ra = a;cout << "a = " << a << endl;cout << "ra = " << ra << endl;cout << "&a = " << &a << endl;cout << "&ra = " << &ra << endl;cout << "sizeof(a)= " << sizeof(a) << endl;cout << "sizeof(ra) = " << sizeof(ra) << endl;return 0; }運行結果:
值相等,地址相等,大小相等,證明了引用在內存中的別名關系。
可以對引用再次取引用,對一個變量建立多個引用,多個引用之間是等價關系。
代碼演示:
運行結果:
應用
取代指針傳參。
C++可以用引用解決的問題,避免用指針來解決。
代碼演示;
#include <iostream>using namespace std;void swapByValue(int a, int b) {int tmp;tmp = a;a = b;b = tmp; }void swapByPtr(int* a, int* b) {int tmp;tmp = *a;*a = *b;*b = tmp; }void swapByRef(int& a, int& b) {int tmp;tmp = a;a = b;b = tmp; }int main() {int a = 3, b = 5;cout << "a = " << a << " b = " << b << endl;swapByRef(a, b);cout << "a = " << a << " b = " << b << endl;return 0; }運行結果:
引用的從宏觀上可以理解為:擴展了變量的作用域,傳參后,就像在本地解決問題一樣。
把一個變量以引用的方式傳到另一個作用域,等價于擴展了該變量的作用域。
避免了傳 n 級指針,解決 n-1 級指針的問題,即平級內解決問題。
存在對指針取引用
代碼演示:
#include <iostream> using namespace std;void swapByRef(char * & a, char * & b) {char * tmp;tmp = a;a = b;b = tmp; }int main() {char* p = "hello";char* q = "world";cout << "p = " << p << " q = " << q << endl;swapByRef(p, q);cout << "p = " << p << " q = " << q << endl;return 0; }運行結果:
不存在對引用取地址
引用的本質:對指針的包裝,避免使用裸露的指針。
設計思想:C++避免對引用再次拆封。
代碼演示:
編譯器報錯:不允許使用指向引用的指針。
存在指針的指針,不存在引用的引用
指針的指針,即二級指針。
C++為了避免 C 語言設計指針的"失誤",避免了引用的引用這種情況,也避免了引用的引用的引用的…的引用的情況。
這種可窮遞歸的設計本身就是有問題的。
代碼演示:存在指針的指針
#include <iostream> using namespace std;int main() {int a;int* p = &a;int** pp = &p;int*** ppp = &pp;int**** pppp = &ppp;//無窮無盡return 0; }代碼演示:不存在引用的引用
#include <iostream> using namespace std;int main() {int a;int & p = a;int&& pp = p; //剎車return 0; }存在指針數組,不存在引用數組
數組名,本身是首元素的地址,若首元素是引用的話,數組名就成了引用的指針,與上面說過的不符,即不存在引用的指針。
代碼演示:存在指針數組
pArr 代表首元素地址,首元素是 &a 指針,則 pArr 是二級指針。
代碼演示:不存在引用數組
#include <iostream> using namespace std;int main() {int a, b, c;int & pArr[] = {a, b ,c};return 0; }編譯器報錯:
pArr 代表首元素地址,首元素是變量名a(可以將a理解為對內存的引用),上面說過不允許對引用取地址。
數組的引用
代碼演示:
#include <iostream> using namespace std;int main() {//數組名的兩重性://1:代表整個數組。//2:代表首元素地址。int array[5] = {1,2,3,4,5};int* const & pr = array; //int* const &cout << pr << endl;cout << array << endl;cout << "sizeof(pr) = " << sizeof(pr) << endl;cout << "sizeof(array) = " << sizeof(array) << endl;for (int i = 0; i < 5; i++){cout << pr[i];}cout << endl;int(&ra)[5] = array;cout << ra << endl;cout << array << endl;cout << "sizeof(ra) = " << sizeof(ra) << endl;cout << "sizeof(array) = " << sizeof(array) << endl;for (int i = 0; i < 5; i++){cout << ra[i];}cout << endl;return 0; }運行結果:
常引用
C++中 const 定義的變量稱為常變量。
const 修飾的變量,有著變量的形式,常量的作用,用作常量,常用于取代#define 定義的宏常量。
#define 宏定義在預處理階段替換,const 常量在匯編階段替換。
常引用的特性
const 的本意,即不可修改。所以,const 對象,只能聲明為 const 引用,使其語義保持一致性。
no-const 對象,既可以聲明為 const 引用,也可以聲明為 no-const 引用。
聲明為 const 引用,則不可以通過 const 引用修改數據。
代碼演示:
#include <iostream> using namespace std; int main() {const int val = 10;//int& rv = val; //err類型不等價const int &rv2 = val;//類型等價int data = 666;int& rd = data;const int& rd2 = data;//非const 對象生命為 const 引用//rd2 = 333; 不可修改cout << "data = " << data << " rd = " << rd << " rd2 = " << rd2 << endl;data = 999; cout << "data = " << data << " rd = " << rd << " rd2 = " << rd2 << endl;return 0; }運行結果:
臨時對象的常引用
臨時對象:不可以取地址的對象。
臨時對象:
代碼演示:臨時對象的常引用
#include <iostream>using namespace std;//臨時變量 即不可取地址的對象int foo() {int a = 66;return a; }int main() {//常量const int& cc = 55;cout << "cc = " << cc << endl;//表達式int a = 3;int b = 5;const int& ret = a + b;cout << "ret = " << ret << endl;//函數返回值const int& ra = foo();cout << "ra = " << ra << endl;//類型不同的變量double d = 100.12;const int& rd = d;cout << "d = " << d << endl;cout << "rd = " << rd << endl;return 0; }運行結果:
臨時對象的常引用本質:產生中間變量。
類型不同的變量常引用本質剖析
代碼演示:
#include <iostream>using namespace std;int main() {double d = 3.14;//int & t = d; err 類型不等價const int& rd = d; //產生中間變量cout << "d = " << d << endl;cout << "rd = " << rd << endl;d = 4.14;cout << "d = " << d << endl;cout << "rd = " << rd << endl;return 0; }運行結果:
本質上 const 引用,引用了一個不可改變的臨時變量,
const int tmp = data; const int & rd = tmp;此時,我們改變了 data 的值,臨時變量 tmp 的值并沒有發生改變。
在能夠使用 const 的地方就使用 cosnt
好處:
引用的本質
引用的本質:C++對指針的包裝,引用即指針。
引用的大小
代碼演示;
#include <iostream>using namespace std;struct TypeP {char* p; };struct TypeC {char c; };struct TypeR {char& r; };int main() {cout << "sizeof(TypeP) = " << sizeof(TypeP) << endl;cout << "sizeof(TypeC) = " << sizeof(TypeC) << endl;cout << "sizeof(TypeR) = " << sizeof(TypeR) << endl;return 0; }運行結果:
引用的類型
C++中只有 const 類型的數據,要求必須初始化。
引用也必須要初始化,所以引用是 const 修飾的指針,一經聲明,不可修改。引用的內容可以修改。所以是:type* const p
結論
引用的本質是 const 類型的指針,即 type* const p。
引用是對指針的封裝。
從微觀角度來說,引用至少需要分配一個指針類型大小的內存空間。
反匯編比對指針和引用
源代碼
代碼演示:
#include <iostream>using namespace std;void swapPtr(int* p, int* q) {int t = *p;*p = *q;*q = t; } void swapRef(int& p, int& q) {int t = p;p = q;q = t; } int main() {int a = 3; int b = 5;swapRef(a, b);swapPtr(&a, &b);return 0; }匯編代碼比對結果
結論
對同一個功能相同的程序,分別采用了指針和引用的兩種方式來進行編寫,匯編得到的結果一致。
證明:引用的本質是對指針的封裝。
總結
以上是生活随笔為你收集整理的想和高手侃侃而谈C++引用?看这一篇就够了【C++引用】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习历程导航
- 下一篇: 取代C语言标准输入输出:cin 和 co