在這里插入圖片描述

①.引用
Ⅰ.引用概念
引用不是新定義一個(gè)變量,而是給已經(jīng)存在的變量取別名,編譯器不會(huì)為引用變量開(kāi)辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存區(qū)間。
比如水滸傳里的李逵
小名叫鐵牛,江湖人稱黑旋風(fēng)。這些都是他,只不過(guò)名字不同。
Ⅱ.引用使用
類(lèi)型& 引用變量名=引用實(shí)體
int main()
{
int a = 10;
int& ra = a;//給變量a取別名為ra
int& rra = ra;//又給變量rra取別名為rra ,其實(shí)本質(zhì)上都是a
printf("%p\n", a);
printf("%p\n", ra);
printf("%p\n", rra);
}
從語(yǔ)法上我們看,就是給a取別名,并沒(méi)有開(kāi)辟空間。
注意:引用類(lèi)型必須和引用實(shí)體是同種類(lèi)型的。
Ⅲ.引用特性
1.一個(gè)變量可以有多個(gè)引用
2.引用在定義時(shí)必須初始化
3.引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體。 C++的引用不能改指向
1.一個(gè)變量可以有多個(gè)引用
就像李逵可以有多個(gè)別名一樣。
int main()
{
int a = 10;
int& ra = a;
int& rra = a;
printf("%p\n", a);
printf("%p\n", ra);
printf("%p\n", rra);//它們的本質(zhì)都是a
}
2.引用在定義時(shí)必須初始化
你要取別名,倒是說(shuō)給誰(shuí)取別名呀,你不說(shuō)誰(shuí)知道這個(gè)名字是誰(shuí)的。
int main()
{
int a=10;
int&ra;//這樣是不可以的,編譯器會(huì)報(bào)錯(cuò)。
//引用在定義時(shí)必須要初始化。
}
3.引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體。
int main()
{
int a = 10;
int&ra=a;
int b=20;
ra=b;//這里ra=b是將b的值賦給ra,而不是讓ra變成b的別名。C++的引用不能改指向。ra仍然是a的別名
}
注意:
同一個(gè)域不能同名引用,不能域里可以同名,但在不同域里是可以同名的,是可以區(qū)分的。
Ⅳ.使用場(chǎng)景
引用第一使用場(chǎng)景:
1.做函數(shù)參數(shù)
void Swap(int*a, int* b)
{
int tmp = a;
a = b;
b = tmp;
}
//引用
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
意義:
1.引用做參數(shù)–【輸出型參數(shù)】
什么叫輸出型參數(shù)呢?就是傳進(jìn)去使用還要帶出來(lái)
這里利用形參就是實(shí)參的變名,改變形參就改變了實(shí)參
不同于傳指針參數(shù)。
2.引用做參數(shù)—【提高效率】
對(duì)于/大對(duì)象/深度拷貝的數(shù)據(jù)是可以提高效率的。
因?yàn)槭且貌婚_(kāi)空間
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
A a;
// 以值作為函數(shù)參數(shù)
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作為函數(shù)參數(shù)
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分別計(jì)算兩個(gè)函數(shù)運(yùn)行結(jié)束后的時(shí)間
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
}
雖然指針也能做到上面的功能。
但是引用更方便。
引用第二大使用場(chǎng)景:
2.做函數(shù)返回值
int fun()//返回值就用int來(lái)接受
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = fun();//最后將返回值返回ret
printf("%d ", ret);
}
沒(méi)有毛病吧。根據(jù)函數(shù)棧幀的創(chuàng)建和銷(xiāo)毀我們知道,在函數(shù)調(diào)用完時(shí),函數(shù)棧幀會(huì)銷(xiāo)毀,而這個(gè)返回值將會(huì)保存在一個(gè)寄存器中,相當(dāng)于一個(gè)臨時(shí)變量。操作系統(tǒng)會(huì)開(kāi)辟一個(gè)臨時(shí)變量來(lái)保存這個(gè)返回值,如何再將臨時(shí)變量賦給ret。最后ret得到了函數(shù)的返回值。
而這個(gè)過(guò)程需要需要?jiǎng)?chuàng)建臨時(shí)變量,那么就需要開(kāi)銷(xiāo)。
其實(shí)只要看函數(shù)返回值,只要是傳值返回的
不管怎么樣編譯器都會(huì)生成臨時(shí)變量。
但是當(dāng)用引用作為返回值時(shí),最后就不需要?jiǎng)?chuàng)建臨時(shí)變量了。
也就是傳引用返回就不會(huì)生成臨時(shí)變量。
int& fun()//用引用作為返回值
{
static int n = 0;
n++;
return n;//最后函數(shù)返回的是n的別名,不需要?jiǎng)?chuàng)建臨時(shí)變量保存,因?yàn)閯e名不需要開(kāi)辟空間
}
int main()
{
int ret = fun();//fun的返回值就是n的別名,別名不需要開(kāi)辟空間,中間沒(méi)有臨時(shí)變量,直接就賦值會(huì)ret了。
printf("%d ", ret);
}
那我們是不是以后函數(shù)返回值都用引用呢?
當(dāng)然不行了,上面的案例也是特殊的,因?yàn)閟tatic修飾的變量在靜態(tài)區(qū),當(dāng)函數(shù)棧幀銷(xiāo)毀時(shí),并不影響變量a,所有當(dāng)引用取別名時(shí)可以找到它。
所以這里打印的ret的值是不確定的。
如果fun函數(shù)結(jié)束,棧幀銷(xiāo)毀,沒(méi)有清理?xiàng)?,那么ret的結(jié)果是僥幸是正確的。
如果fun函數(shù)結(jié)束,棧幀銷(xiāo)毀,清理?xiàng)?,那么ret的結(jié)果是隨機(jī)值。
意義:
1.減少拷貝,提高效率
但要記住并不是任何地方都可以引用返回值
當(dāng)函數(shù) 返回值為局部變量時(shí),這種是不行的。
因?yàn)榉祷鼐植繉?duì)象引用很危險(xiǎn)。最后的結(jié)果取決于函數(shù)調(diào)用完棧幀銷(xiāo)毀不銷(xiāo)毀
當(dāng)返回值為靜態(tài)變量時(shí)不危險(xiǎn),函數(shù)調(diào)用結(jié)束,函數(shù)棧幀銷(xiāo)毀不影響靜態(tài)變量的存在。
不會(huì)有隨機(jī)值的問(wèn)題。靜態(tài)變量還在,那么取別名就合法。
傳引用返回–沒(méi)有創(chuàng)建臨時(shí)變量,只是取別名。別名==變量。
返回變量的別名,沒(méi)有臨時(shí)變量,也沒(méi)有拷貝。所以可以提高效率。
傳值返回–需要開(kāi)辟臨時(shí)變量-再拷貝回去。
引用返回門(mén)檻:不能隨意引用傳參返回
1.基本任何場(chǎng)景都可以用引用傳參
2.但要謹(jǐn)慎用引用返回,出了函數(shù)作用域,對(duì)象不在, 就不能用引用返回,還在就能用。
2.查改返回值
引用做返回值,可以修改返回值,和獲取返回值。
因?yàn)榉祷刂稻褪沁@個(gè)要修改或者要返回變量的別名,對(duì)別名修改或者獲取。就是修改該變量。
Ⅵ.常引用
1.引用過(guò)程中,權(quán)限不能放大
int main()
{
1.//引用過(guò)程中,權(quán)限不能放大
const int a = 0;//表示a不能修改
int& b = a;//不能通過(guò)引用別名來(lái)修改a,這種方法是錯(cuò)誤的。
2.//引用過(guò)程中,權(quán)限是可以平移或縮小的。
int x=0;
int &y=x;
const int&z=x;
3.//對(duì)z這個(gè)別名進(jìn)行修飾,也就是z這個(gè)別名權(quán)限縮小了。但其他別名的權(quán)限還是正常的。
++x;
}
2.不能引用帶有常性的變量。
double a=1.2;
int b=a;
//其實(shí)在類(lèi)型轉(zhuǎn)化會(huì)產(chǎn)生臨時(shí)變量,產(chǎn)生一個(gè)int 類(lèi)型的臨時(shí)變量
int&bb=a;
//這個(gè)也是一樣,a是double類(lèi)型,別名bb是int類(lèi)型,發(fā)生類(lèi)型轉(zhuǎn)化,然后產(chǎn)生一個(gè)臨時(shí)變量存在著dd,這個(gè)dd就具有常性了,因?yàn)榕R時(shí)變量具有常性。
而帶有常性的變量就不能使用引用了。
Ⅶ.引用與指針區(qū)別
1.引用在語(yǔ)法概念上就是一個(gè)別名,沒(méi)有開(kāi)辟空間,和其引用的實(shí)體共用同一塊空間。
2.但在底層實(shí)現(xiàn)上,引用其實(shí)是有空間的,因?yàn)橐檬前凑罩羔樂(lè)绞絹?lái)實(shí)現(xiàn)的。
不同點(diǎn):
-1.引用概念上是定義一個(gè)變量的別名,指針是存儲(chǔ)一個(gè)變量的的地址
-2.引用在定義時(shí),需要初始化,指針沒(méi)有要求。
-3.引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在如何時(shí)候指向任何一個(gè)同類(lèi)型實(shí)體。
-4.沒(méi)有NULL引用概念,但有NULL指針-5.有多級(jí)指針,但是沒(méi)有多級(jí)引用。
-6.引用比指針使用起來(lái)更安全。
-8.在sizeof下含義不相同:在引用用計(jì)算的就是別名類(lèi)型的大小,而指針是固定的,始終是地址空間所占字節(jié)個(gè)數(shù)。(32位下4字節(jié))
-9.引用自加表示引用的實(shí)體加1,而指針自加,表示指針向后偏移一個(gè)類(lèi)型的大小。
②.auto關(guān)鍵字
在C++11中,auto的作用是作為一個(gè)新的類(lèi)型指示符來(lái)指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。
int a = 0;
auto b = a;//auto可以自動(dòng)識(shí)別a的類(lèi)型
auto c = 's';//自動(dòng)識(shí)別字符‘s’的類(lèi)型
還有要注意在使用auto時(shí)定義變量時(shí),必須要對(duì)其進(jìn)行初始化
int a=0;
auto b;//使用auto卻不初始的編譯器會(huì)報(bào)錯(cuò)
auto c ;//這樣不初始化是不對(duì)的。
【注意】
在使用auto定義變量時(shí),必須對(duì)其初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來(lái)推到auto的實(shí)際類(lèi)型,因此auto并非是一種”類(lèi)型“聲明,而是一個(gè)類(lèi)型聲明時(shí)的”占位符“,編譯器在編譯期會(huì)將auto替換為變量實(shí)際的類(lèi)型。
1.使用規(guī)則
1.auto與指針和引用結(jié)合使用
用auto聲明指針類(lèi)型時(shí),用auto和auto沒(méi)有區(qū)別。*
但用auto聲明引用類(lèi)型時(shí),必須加上&。
int a=0;
auto pa=&a;//auto與指針和引用結(jié)合使用
auto* pa = &a;
auto&ra=a;
2.在同一行定義多個(gè)變量。
當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類(lèi)型,否則編譯器會(huì)報(bào)錯(cuò),因?yàn)榫幾g器實(shí)際只對(duì)第一個(gè)類(lèi)型進(jìn)行推導(dǎo),然后用推導(dǎo)出來(lái)的類(lèi)型定義其他變量。
auto a = 1, b = 2;
auto c = 3, d = 4.0;//這樣就不對(duì)了,auto一行定義多個(gè)變量雖然可以,但是要求這一行變量類(lèi)型都相同才可以。d的類(lèi)型與c不同
3.auto不能作為函數(shù)的參數(shù)。
void fun(auto a)//這種寫(xiě)法是不允許的
{}
4.auto不能直接用來(lái)聲明數(shù)組
int a[]={6,5,4};
auto c={9,8,7};//這種寫(xiě)法是不允許的。
③.基于范圍的for循環(huán)
如果我們想要打印一個(gè)數(shù)組,就必須遍歷這個(gè)數(shù)組,而遍歷這個(gè)數(shù)組就得需要知道這個(gè)數(shù)組的大小是多少。
int main()
{
int a[] = { 9,8,7,6,5,4,3,2,1 };
int n = sizeof(a) / sizeof(a[0]);
for (int i = 0; i < n; i++)
{
cout << a[i] << endl;
}
return 0;
}
而對(duì)于我們來(lái)說(shuō),這種寫(xiě)法有時(shí)會(huì)出現(xiàn)很多問(wèn)題,比如數(shù)組大小計(jì)算錯(cuò)誤,或者循環(huán)條件寫(xiě)錯(cuò),所以C++11中引入了基于范圍的for循環(huán)。
for循環(huán)后面的括號(hào)由冒號(hào)" :"分為兩個(gè)部分,第一部分是范圍內(nèi)用于迭代的變量類(lèi)型,第二部分則表示被迭代的范圍。
for(auto__:__)
;
int arr[] = { 9,8,7,5,6,3,2,4 };
for (auto e : arr)
{
cout << e << endl;
}
1.使用規(guī)則
1.使用于數(shù)組
2.依次取數(shù)組中的數(shù)據(jù)賦值給e(這里的e可以隨便寫(xiě)其他,沒(méi)有規(guī)定,可以是x,可以是y)
3.自動(dòng)迭代,自動(dòng)判斷結(jié)束。
4.與普通循環(huán)類(lèi)似,可以用continue來(lái)結(jié)束本次循環(huán),也可以用break跳出整個(gè)循環(huán)。
還有如果想要利用范圍for改變數(shù)組內(nèi)容該任何改變呢?
如果想讓數(shù)組內(nèi)數(shù)據(jù)都變成2倍這樣寫(xiě)可以嗎?
int arr[] = { 9,8,7,5,6,3,2,4 };
for (auto x : arr)
{
x * 2;
}
要注意,這里只是將arr數(shù)組內(nèi)容依次賦值給x,但x改變能改變數(shù)組內(nèi)的數(shù)據(jù)嗎?當(dāng)然不能了。
所以我們想要改動(dòng)數(shù)組內(nèi)的數(shù)據(jù),只要傳引用即可,每次改變的是數(shù)組數(shù)據(jù)的別名。改變別名就改變了數(shù)組數(shù)據(jù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-420862.html
int arr[] = { 9,8,7,5,6,3,2,4 };
for (auto& x : arr)
{
x * 2;
}
【注意】
for循環(huán)迭代的范圍必須是確定的
對(duì)于數(shù)組而言,就是數(shù)組中第一個(gè)元素和最后一個(gè)元素的范圍;對(duì)于類(lèi)而言,應(yīng)該提供
begin和end的方法,begin和end就是for循環(huán)迭代的范圍。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-420862.html
到了這里,關(guān)于【C++入門(mén)必備知識(shí):|引用| +|auto關(guān)鍵字| + |范圍for|】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!