中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

廣州開發(fā)區(qū)建設(shè)和環(huán)境保護網(wǎng)站網(wǎng)站seo運營

廣州開發(fā)區(qū)建設(shè)和環(huán)境保護網(wǎng)站,網(wǎng)站seo運營,怎樣顯示隱藏的圖標wordpress,如何在百度上做自己的網(wǎng)站目錄 一. 什么是引用 1.1 引用的概念 1.2 引用的定義 二. 引用的性質(zhì)和用途 2.1 引用的三大主要性質(zhì) 2.2 引用的主要應(yīng)用 三. 引用的效率測試 3.1 傳值調(diào)用和傳引用調(diào)用的效率對比 3.2 值返回和引用返回的效率對比 四. 常引用 4.1 權(quán)限放大和權(quán)限縮小問題 4.2 跨…

目錄

一.?什么是引用

1.1?引用的概念

1.2?引用的定義

二.?引用的性質(zhì)和用途

2.1?引用的三大主要性質(zhì)

2.2?引用的主要應(yīng)用?

三. 引用的效率測試

3.1?傳值調(diào)用和傳引用調(diào)用的效率對比

3.2?值返回和引用返回的效率對比

四.?常引用?

4.1 權(quán)限放大和權(quán)限縮小問題

4.2?跨數(shù)據(jù)類型的引用問題

五.?引用和指針的區(qū)別


一.?什么是引用

1.1?引用的概念

引用,通俗的講,就是給已經(jīng)存在的變量取一個別名,而不是創(chuàng)建一個新的變量。引用和被引用對象共同使用一塊內(nèi)存空間。

引用就好比一個人的大名和小名,大名和小名都是一個人。再比如,李逵外號黑旋風(fēng),叫李逵和黑旋風(fēng)表示同一個人。

1.2?引用的定義

引用定義的語法格式:類型&?引用的名稱 =?被引用實體

如,定義int a = 10,希望再定義一個引用b,來表示整形變量a的別名,語法為:int& b = a。演示代碼1.1展示了引用的定義過程,對原變量a和引用b的其中任意一個賦值,都會使a和b的值均發(fā)生改變,這是因為a和b共用一塊內(nèi)存空間。

演示代碼1.1:

int main()
{int a = 10;int& b = a;  //b是a的引用(別名)printf("a = %d, b = %d\n", a, b);  //10,10a = 20;  //對a賦值,同時改變a和bprintf("a = %d, b = %d\n", a, b);  //20,20b = 30;  //對b賦值,同時改變a和bprintf("a = %d, b = %d\n", a, b);  //30,30return 0;
}
圖1.1?演示代碼1.1的運行結(jié)果

二.?引用的性質(zhì)和用途

2.1?引用的三大主要性質(zhì)

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

定義引用時必須給出這個引用的被引用實體是誰,如:int &b; -- 是非法的。

演示代碼2.1:

int main()
{int a = 10;int& b;  //報錯int& c = a;  //初始化引用return 0;
}
圖2.1? 演示代碼2.1的報錯信息

?2、一個變量可以有多個引用

我們可以為一個變量取多個別名。如演示代碼2.2所示,給a變量取b、c、d三個別名是可行的。對a、b、c、d中的任意一個賦值,都會使a、b、c、d的值均發(fā)生改變。a、b、c、d共用一塊內(nèi)存空間。

演示代碼2.2:

int main()
{int a = 10;int& b = a;int& c = a;int& d = a;  //為a取b、c、d三個別名printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);  //10,10,10,10c = 20;printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);  //20,20,20,20return 0;
}
圖2.2? 演示代碼2.2的運行結(jié)果

?3、一個引用一旦引用了某個實體,就不能再引用其他實體

演示代碼2.3中的b = c并不是將b變?yōu)樽兞縞的引用,而是將變量c的值賦給b,通過打印b和c的地址,我們可以發(fā)現(xiàn)b和c并不共用一塊內(nèi)存空間,而賦值之后,a和b的值都變?yōu)榱?0。

演示代碼2.3:

int main()
{int a = 10;int& b = a;int c = 20;b = c;   //將c的值賦給b,而不是讓b變?yōu)閏的引用printf("&b = %p, &c = %p\n", &b, &c);   //b和c的地址不一致printf("a = %d, b = %d\n", a, b);  //a、b都變?yōu)榱薱的值20return 0;
}
圖2.3? 演示代碼2.3的運行結(jié)果

正是因為引用一旦引用了某個實體之后就不能再引用其他實體,所以引用無法替代指針來實現(xiàn)鏈表數(shù)據(jù)結(jié)構(gòu)。否則就無法實現(xiàn)鏈表的增、刪等操作,鏈表的增刪操作需要改變指針的指向。

2.2?引用的主要應(yīng)用?

1、引用做函數(shù)參數(shù)

要寫一個swap函數(shù),實現(xiàn)兩個整形數(shù)據(jù)的交換,如果用C語言來寫這個函數(shù),就必須使用指針來作為函數(shù)的參數(shù),即:void swap(int* px, int* py)。但是,如果使用C++來寫,則可以用引用傳參來替代指針傳參,因為引用和被引用實體共用一塊內(nèi)存空間,引用傳參使得函數(shù)內(nèi)部可以控制實參所占用的內(nèi)存空間,這是,swap可以聲明為:void swap(int& rx, int& ry)。

演示代碼2.4:

void swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}int main()
{int x = 10, y = 20;printf("交換前:x = %d,y = %d\n", x, y);  //10,20swap(x, y);printf("交換后:x = %d,y = %d\n", x, y);  //20,10return 0;
}
圖2.4? 演示代碼2.4的運行結(jié)果

至此,可以總結(jié)出函數(shù)的三種調(diào)用方法:?

  1. 傳值調(diào)用。
  2. 傳地址調(diào)用。
  3. 傳引用調(diào)用。

?問題:void swap(int x, int y)和void swap(int& x, int& y)能否構(gòu)成函數(shù)重載?

答案是可以的。因為其滿足構(gòu)成函數(shù)重載的條件之一 :參數(shù)的類型不同。

但是,在調(diào)用這兩個swap函數(shù)時,會存在歧義。通過語句swap(x,y)調(diào)用,無法確定是調(diào)用swap(int x, int y)還是swap(int&x, int& y)。

2、引用做函數(shù)的返回值

在演示代碼2.5中,定義函數(shù)int& Add(int x, int y),函數(shù)返回z的別名。我們希望這個函數(shù)能夠?qū)+y進行計算。但是顯然,這段代碼是有潛在問題的,因為在add函數(shù)調(diào)用結(jié)束后,為add函數(shù)創(chuàng)建的棧幀會被銷毀,這塊棧空間會還給操作系統(tǒng)。此時再使用add函數(shù)的返回值,就會造成對內(nèi)存空間的非法訪問,而大部分情況下,編譯器不會對非法訪問內(nèi)存報錯。

演示代碼2.5:

int& add(int x, int y)
{int z = x + y;return z;
}int main()
{int& ret = add(1, 2);printf("ret = %d\n", ret);return 0;
}

對于演示代碼2.5的運行結(jié)果,可以分為兩種情況討論:

  • 函數(shù)棧幀銷毀后,編譯器不對被銷毀的??臻g進行清理,打印函數(shù)的返回值,結(jié)果依舊為x + y的值。
  • 函數(shù)棧幀銷毀后,編譯器對被銷毀的??臻g進行清理,函數(shù)的返回值為隨機值。

在VS2019 編譯環(huán)境下,演示代碼2.5的運行結(jié)果為3,說明VS編譯器不會清理被銷毀的函數(shù)棧幀空間中內(nèi)容。

圖2.5? 演示代碼2.5的運行結(jié)果

既然VS編譯器不會對被銷毀的函數(shù)棧幀進行清理,那么是否在VS編譯環(huán)境下,可以正常使用演示代碼2.5中的add函數(shù)呢?答案顯然是否定的,這可以從以下兩個方面解釋:

  • 如果在其他編譯環(huán)境下進行編譯,則被銷毀的函數(shù)空間可能會被清理,這樣會降低代碼的可移植性。
  • 即使函數(shù)棧幀空間不被清理,但這塊空間已經(jīng)換給了操作系統(tǒng),如果調(diào)用完add函數(shù)后再調(diào)用其他函數(shù),那么原本為z開辟的空間可能會被覆蓋,從而改變ret的值。

如演示代碼2.6所示,第一次調(diào)用add函數(shù)使用ret來接收返回值,第二次調(diào)用add函數(shù)不接收返回值。但是第二次調(diào)用add函數(shù)之后,ret的值卻變?yōu)榱?0,這是因為第二次調(diào)用add函數(shù)覆蓋了第一次調(diào)用時創(chuàng)建的函數(shù)棧幀,原來第一次調(diào)用存放變量z的內(nèi)存空間的內(nèi)容由3變?yōu)榱?0,因此,程序運行的結(jié)果為30。這段代碼在運行過程中棧幀的創(chuàng)建和銷毀情況見圖2.7。

演示代碼2.6:

int& add(int x, int y)
{int z = x + y;return z;
}int main()
{int& ret = add(1, 2);cout << ret << endl;add(10, 20);cout << ret << endl;return 0;
}
圖2.6?演示代碼2.6的運行結(jié)果
圖2.7? 兩次調(diào)用add函數(shù)棧幀的開辟和被覆蓋情況

總結(jié)(什么時候可以用引用返回,什么時候不可以):

  • 如果出了函數(shù)作用域,函數(shù)返回的對象被銷毀了,則不能使用引用類型作為返回值。
  • 如果出了函數(shù)作用域,函數(shù)的返回對象還沒有被銷毀(存儲返回對象的內(nèi)存還沒有還給操作系統(tǒng)),則可以使用引用作為返回值。

演示代碼2.7給出了兩種可以使用引用作為返回的情況,一種是以靜態(tài)變量作為返回對象,另一種是返回對象為調(diào)用函數(shù)中開辟的一塊內(nèi)存空間中的內(nèi)容(調(diào)用函數(shù)中開辟的數(shù)組)。

演示代碼2.7:

int& func1()
{static int n = 0;++n;return n;
}char& func2(char* str, int i)
{return str[i];
}int main()
{cout << func1() << endl;  //1cout << func1() << endl;  //2char ch[] = "abcdef";for (int i = 0; i < strlen(ch); ++i){func2(ch, i) = '0' + i;}cout << ch << endl;  //012345return 0;
}
圖2.8? 演示代碼2.7的運行結(jié)果

思考問題:既然函數(shù)完成調(diào)用時才會返回,而調(diào)用完成時函數(shù)棧幀又會被銷毀。那么,以值作為函數(shù)返回類型時,時如何從函數(shù)中接收返回值的呢?

就比如演示代碼2.8中的add函數(shù),函數(shù)返回值時add函數(shù)中的臨時變量z的值,在主函數(shù)中的ret如何從add函數(shù)中接收z值。

演示代碼2.8:?

int add(int x, int y)
{int z = x + y;return z;
}int main()
{int ret = add(2, 3);return 0;
}

答案其實很簡單,ret并不是直接從add函數(shù)棧幀的空間中接收返回值,而是在add函數(shù)完成調(diào)用、函數(shù)棧幀銷毀之前,存儲一個臨時變量用于接收函數(shù)的返回值,然后在將臨時變量的值賦給ret。

那么,這個臨時變量存儲在什么位置呢?分兩種情況討論:

  • 如果返回值比較小,則使用寄存器充當(dāng)臨時變量。
  • 如果返回值比較大,則將臨時變量放在調(diào)用add函數(shù)的函數(shù)內(nèi)部,在調(diào)用add函數(shù)之前在調(diào)用add的函數(shù)的棧幀中預(yù)先開辟一塊空間用于存儲臨時變量。
圖2.9? 值返回情況下函數(shù)返回值被接收的過程

三. 引用的效率測試

3.1?傳值調(diào)用和傳引用調(diào)用的效率對比

演示代碼3.1分別執(zhí)行100000次傳值調(diào)用和100000次傳引用調(diào)用,每次傳值調(diào)用傳給函數(shù)的形參的大小為40000bytes,記錄傳值調(diào)用和傳引用調(diào)用消耗的時間。

程序運行結(jié)果顯示,10000次傳值調(diào)用耗時71ms,100000次傳引用調(diào)用耗時2ms,傳引用調(diào)用的效率遠高于傳值調(diào)用。這是因為傳引用調(diào)用不用再為形參開辟一塊內(nèi)存空間,而為形參開辟空間存在一定的時間消耗。

演示代碼3.1:

#include<iostream>
#include<time.h>
using namespace std;//大小為40000bytes的結(jié)構(gòu)體
typedef struct A
{int arr[10000];
}A;void Testvaluefunc(A a) { };   //傳值調(diào)用測試函數(shù)
void TestReffunc(A& a) { };  //傳引用調(diào)用測試函數(shù)void TestRefAndValue1()
{A a;int i = 0;size_t begin1 = clock();  //記錄開始傳值調(diào)用的時間(傳值調(diào)用100000次)for (i = 0; i < 100000; ++i){Testvaluefunc(a);}size_t end1 = clock();  //記錄結(jié)束傳值調(diào)用的時間size_t begin2 = clock();  //記錄開始傳引用調(diào)用的時間(調(diào)用100000次)for (i = 0; i < 100000; ++i){TestReffunc(a);}size_t end2 = clock();cout << "傳值調(diào)用10000次耗費時間:" << end1 - begin1 << endl;cout << "傳引用調(diào)用10000次耗費時間:" << end2 - begin2 << endl;
}
圖3.1? 演示代碼3.1的運行結(jié)果

3.2?值返回和引用返回的效率對比

演示代碼3.2分別執(zhí)行100000次值返回函數(shù)和100000次引用返回函數(shù),記錄調(diào)用值返回函數(shù)和調(diào)用引用返回函數(shù)消耗的時間。程序運行結(jié)果表明,調(diào)用100000次值返回函數(shù)耗時136ms,調(diào)用100000次引用返回函數(shù)耗時2ms,引用返回的效率遠高于值返回。

演示代碼3.2:

#include<iostream>
#include<time.h>
using namespace std;typedef struct A
{int arr[10000];
}A;A a;A TestValuefunc2()
{return a;
}A& TestReffunc2()
{return a;
}void TestRefAndValue2()
{int i = 0;size_t begin1 = clock();  //記錄開始時間(調(diào)用100000次)for (i = 0; i < 100000; ++i){TestValuefunc2();}size_t end1 = clock();  //記錄結(jié)束時間size_t begin2 = clock();  //記錄開始的時間(調(diào)用100000次)for (i = 0; i < 100000; ++i){TestReffunc2();}size_t end2 = clock();  //記錄結(jié)束時間cout << "以值作為返回:" << end1 - begin1 << "ms" << endl;cout << "以引用作為返回:" << end2 - begin2 << "ms" << endl;
}int main()
{TestRefAndValue2();  //引用作為返回和值作為返回的效率測試return 0;
}
圖3.2? 演示代碼3.2的運行結(jié)果

四.?常引用?

4.1 權(quán)限放大和權(quán)限縮小問題

如果int& b = a,而a是整形常量,被const關(guān)鍵字修飾,那么b就不能作為a的別,因為a變量是只讀的,而將b定義為int&類型,則表明b是可讀可寫的類型,b對a存在權(quán)限放大問題。

對于int a = 10,使用const?int& b = a來表示a的別名是可以編譯通過的。因為a為讀寫類型,而b為只讀類型,b相對于a權(quán)限縮小,C++允許權(quán)限縮小。

總結(jié):C++允許權(quán)限縮小,不允許權(quán)限放大。

演示代碼4.1:

int main()
{//權(quán)限放大問題const int a = 10;//int& b = a;   //報錯const int& b = a;  //編譯通過//權(quán)限縮小int c = 10;const int& d = c;   //能夠編譯通過return 0;
}

4.2?跨數(shù)據(jù)類型的引用問題

看一個很詭異的問題。在演示代碼4.2中,定義一個雙精度浮點型數(shù)據(jù)double d = 1.1,編譯程序,出現(xiàn)下面的現(xiàn)象:

  • 將d賦給int型數(shù)據(jù)i1,編譯通過。
  • 用int&?i2 = d來作為d的引用(別名),編譯報錯。
  • 但是,使用const int& i3 = d來作為d的引言,編譯通過。

演示代碼4.2:

int main()
{double d = 11.11;int i1 = d;  //強轉(zhuǎn),編譯通過//int& i2 = d;   //編譯報錯const int& i3 = d;  //編譯通過printf("&d = %p\n", &d);printf("&i3 = %p\n", &i3);return 0;
}

那么,為什么const?int& i3類型的可以作為d的引用,而int& i2卻不行?問題出在強制類型轉(zhuǎn)換上。要理解這個問題,首先要清楚強制類型轉(zhuǎn)換的過程,強制類型轉(zhuǎn)換(int i1 = d),并不是將d強轉(zhuǎn)后的數(shù)據(jù)直接賦給i1,而是先將d強轉(zhuǎn)為int類型數(shù)據(jù)的值存儲在一個臨時變量中,然后再將臨時變量的值傳給i1,詳見圖4.1。

圖4.1?數(shù)據(jù)強制類型轉(zhuǎn)換的過程

臨時變量具有常性,只可讀不可改。因此,int& i2 = d就存在權(quán)限放大的問題,編譯無法通過,而const?int& i3 = d不會存在權(quán)限放大的問題,可以編譯通過。但是,這里的i3就不再是d的別名,而是存儲d強轉(zhuǎn)為int類型數(shù)據(jù)值的臨時變量的別名,因此i3和d的地址也就不同。演示代碼4.2打印了i3和d的地址,表面他們不同,i3其實并不是d的別名。

提示:一定要弄清楚強轉(zhuǎn)類型轉(zhuǎn)換時臨時變量做中間值的問題!

圖4.2? 演示代碼4.2的運行結(jié)果

五.?引用和指針的區(qū)別

  1. 引用是定義一個變量的別名,而指針存儲一個地址。
  2. 引用不占用額外的內(nèi)存空間,而指針要占用4bytes或8bytes的內(nèi)存空間。
  3. 引用在定義時必須初始化,而指針可以不初始化。(建議指針在定義時避免不初始化)。
  4. 引用一旦引用了某個實體,便不能更改被引用實體,而指針可以更改指向。
  5. 對引用自加,即對被引用的實體+1,指針自加,向后偏移一個指針類型的大小(bytes)。
  6. 沒有多級引用,有多級指針。
  7. 訪問實體時,引用直接由編譯器處理即可,指針需要解應(yīng)用。
  8. 沒有空引用,但有空指針NULL。
  9. 引用相對于指針更加安全。

因為指針存在野指針、空指針等問題,造成指針過于靈活,所以指針的安全性不如引用。

引用的底層是通過指針來實現(xiàn)的。

引用最大的局限性在于不能更改引用實體,因此雖然引用的底層是通過指針實現(xiàn)的,但引用不能替代指針來實現(xiàn)鏈表數(shù)據(jù)結(jié)構(gòu)。因為鏈表的操作需要更改指針的指向。

http://www.risenshineclean.com/news/8715.html

相關(guān)文章:

  • 十九歲日本電影免費完整版觀看天津seo數(shù)據(jù)監(jiān)控
  • 如果做網(wǎng)站推廣深圳網(wǎng)站開發(fā)技術(shù)
  • 網(wǎng)站二級頁面做哪些東西百度網(wǎng)址大全舊版安裝
  • wordpress新聞網(wǎng)站南昌seo營銷
  • 上海模板建站多少錢國內(nèi)十大4a廣告公司
  • 自己做的網(wǎng)站不備案行嗎手機關(guān)鍵詞seo排名優(yōu)化
  • 電子商務(wù)網(wǎng)站業(yè)務(wù)流程網(wǎng)站域名解析ip查詢
  • 咸陽做網(wǎng)站電話青島網(wǎng)站建設(shè)方案
  • 有幾家做網(wǎng)站的公司好谷歌商店paypal官網(wǎng)下載
  • 東莞網(wǎng)站營銷推廣公司鄭州seo培訓(xùn)班
  • 網(wǎng)站建設(shè)合同前期需注意哪些問題百度app登錄
  • wordpress怎么被百度收錄福州seo按天收費
  • 做軟件的網(wǎng)站情感營銷的十大案例
  • 哪個網(wǎng)站可以做服裝批發(fā)站內(nèi)優(yōu)化包括哪些
  • 網(wǎng)頁制作免費網(wǎng)站建設(shè)的搜索引擎優(yōu)化
  • 網(wǎng)站開發(fā)項目的wbsseo文章關(guān)鍵詞怎么優(yōu)化
  • 做puzzle的網(wǎng)站香飄飄奶茶軟文
  • 深圳布吉網(wǎng)站建設(shè)百度指數(shù)官網(wǎng)移動版
  • 成都工裝裝修設(shè)計公司seo站外優(yōu)化平臺
  • org網(wǎng)站建設(shè)廣告外鏈購買交易平臺
  • 溫州專業(yè)網(wǎng)站托管網(wǎng)絡(luò)熱詞的利弊
  • 網(wǎng)站成立時間搜索優(yōu)化軟件
  • 建設(shè)網(wǎng)站代碼電商熱門關(guān)鍵詞
  • 眉山手機網(wǎng)站建設(shè)每天4元代發(fā)廣告
  • 廣州建設(shè)工程交易中心改版seo推廣公司排名
  • 麗水專業(yè)網(wǎng)站建設(shè)價格手機百度下載安裝
  • 建設(shè)銀行忘記密碼網(wǎng)站網(wǎng)站關(guān)鍵詞快速排名優(yōu)化
  • 保健品網(wǎng)站怎么做的如何找友情鏈接
  • 小面網(wǎng)站建設(shè)搜索引擎優(yōu)化方式
  • 網(wǎng)站引導(dǎo)動畫深圳網(wǎng)絡(luò)營銷推廣