目錄
?前言
?1. 引用
? 1.1 引用的概念?
?1.2 引用的特性
?1.3 引用的權(quán)限
?1.4 引用的使用
?1.5 引用與指針的區(qū)別
2. 內(nèi)聯(lián)函數(shù)
2.1? 什么是內(nèi)聯(lián)函數(shù)
2.2? 內(nèi)聯(lián)函數(shù)的特性
?3. auto關(guān)鍵字
?3.1 auto簡(jiǎn)介
?3.2 auto使用規(guī)則
?3.3 auto不能使用的場(chǎng)景
4.? 基于范圍的for循環(huán)
?4.1 范圍for使用
?4.2 使用條件
5. C++空指針?
總結(jié)
?前言
????????在學(xué)習(xí)C語言時(shí),大家或許都被指針為難過,在使用指針時(shí)也存在各種問題,比如:空指針野指針問題(指針可以在任何時(shí)候指向任何地址,包括無效地址)。此外在C語言中函數(shù)調(diào)用時(shí),如果多次的調(diào)用同一函數(shù),創(chuàng)建大量的函數(shù)棧幀就會(huì)導(dǎo)致性能下降,對(duì)于這些缺點(diǎn),C++都進(jìn)行了優(yōu)化與改進(jìn)。那么本期的 “主角” 就是引用&內(nèi)聯(lián)函數(shù)。
?1. 引用
? 1.1 引用的概念?
?????????引用是C++中的一個(gè)重要概念,它是一個(gè)已存在變量的別名,引用不是新定義一個(gè)變量,編譯器不會(huì)為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。對(duì)引用的操作實(shí)際上就是對(duì)原變量的操作。
引用的定義方式為:類型& 引用名 = 原變量名;?
?比如:
int main()
{
int a = 1;
int& b = a;
a++;
b++;//b++也就是a++
cout << a << endl;//輸出3
return 0;
}
注意:引用類型必須和引用實(shí)體是同種類型的。
?1.2 引用的特性
- 引用必須初始化
- 不占用額外空間(它引用的變量共用同一塊內(nèi)存空間)
- 不能修改引用的綁定(引用一旦引用一個(gè)實(shí)體,就不能再引用其他實(shí)體)
- 引用可作為函數(shù)參數(shù)和返回值?
int main()
{
int a = 1;
int b = a;
//int& t;出現(xiàn)報(bào)錯(cuò)
int& c = a;
int& d = a;
int& e = c;
//地址相同
cout << &a << endl;
cout << &c << endl;
cout << &d << endl;
cout << &e << endl;
return 0;
}
?1.3 引用的權(quán)限
?????????在C++中,引用的權(quán)限與指針類似,可以分為兩種權(quán)限:常量引用和非常量引用。
? ? ? ? ?常量引用:使用const修飾的引用被稱為常量引用。常量引用只能讀取被引用變量的值,不能修改被引用變量的值。
????????如果引用實(shí)體使用const修飾,那引用也必須使用const修飾。也就是權(quán)限可以被縮小,但不可以被放大。
比如:
int main()
{
const int a = 1;
//int& b = a;出現(xiàn)報(bào)錯(cuò),權(quán)限被放大
//權(quán)限要等大
const int a = 1;
const int& b = a;
//權(quán)限可以縮小
int c = 2;
const int& d = c;
return 0;
}
除此之外,在類型轉(zhuǎn)換時(shí)創(chuàng)建的臨時(shí)變量也具有常屬性。
int main()
{
int i = 1;
double j = i;
//double& rj = i;//報(bào)錯(cuò)
//類型轉(zhuǎn)換過程中
//存在隱式轉(zhuǎn)換產(chǎn)生臨時(shí)變量,這里的臨時(shí)變量具有常性
const double& rj = i;
return 0;
}
?1.4 引用的使用
? ??做參數(shù)
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
?和指針相比
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
?使用上更加簡(jiǎn)潔,并且引用的傳值效率也很高,比如我們傳值時(shí)傳一個(gè)較大的數(shù)組,傳值調(diào)用將一個(gè)很大內(nèi)存的數(shù)組轉(zhuǎn)換為數(shù)組地址傳過去(變?yōu)?字節(jié))
struct A{ int a[10000]; };
void Func1(A a){}
void Func2(A& a){}
?這些指針可以完成的工作,引用也可以完成。
? ?做返回值
int& Add(int a, int b)
{
static int c = a + b;
return c;
}
在之前我們先來理解一下傳值返回:
int Count()
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = Count();
cout << ret << endl;
return 0;
}
? ? 這里返回的n是Count函數(shù)里的n嗎?答案不是,在C語言函數(shù)中,函數(shù)執(zhí)行結(jié)束函數(shù)內(nèi)創(chuàng)建的變量就會(huì)銷毀,所以這里返回的是Count()函數(shù)中變量n數(shù)值的拷貝(返回的是n的值(臨時(shí)變量),而不是n這個(gè)變量)。
int& Count()
{
int n = 0;
n++;
return n;
}
? ? ? 如果使用引用做返回值,返回的就是n的別名,也可以理解為返回的就是n這個(gè)變量(會(huì)報(bào)警告:返回局部變量或臨時(shí)變量的地址: n)。這樣直接返回函數(shù)內(nèi)變量是很危險(xiǎn)的,因?yàn)楹瘮?shù)內(nèi)的n出了函數(shù)作用域就被銷毀了,再返回原本的n地址處的數(shù)據(jù),此時(shí)數(shù)據(jù)是不可控的。
int main()
{
int& ret = Count();
cout << ret << endl;//第一次輸出還是正常值1
cout << ret << endl;//第二次輸出就變成隨機(jī)值了
}
?1.5 引用與指針的區(qū)別
?在語法概念上引用就是一個(gè)別名,沒有獨(dú)立空間,和其引用實(shí)體共用同一塊空間
int main()
{
int a = 10;
int& ra = a;
cout << "&a = " << &a << endl;//輸出的地址相同
cout << "&ra = " << &ra << endl;
return 0;
}
?在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)?strong>引用是按照指針方式來實(shí)現(xiàn)的
?下邊是引用與指針底層匯編的對(duì)比:
引用與指針的不同點(diǎn):
- 引用概念上定義一個(gè)變量的別名,指針存儲(chǔ)一個(gè)變量地址。
- 引用在定義時(shí)必須初始化,指針沒有要求
- 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時(shí)候指向任何一個(gè)同類型實(shí)體
- 沒有NULL引用,但有NULL指針
- 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個(gè)數(shù)(32
位平臺(tái)下占4個(gè)字節(jié)) - 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類型的大小
- 有多級(jí)指針,但是沒有多級(jí)引用
- 訪問實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
- 引用比指針使用起來相對(duì)更安全
2. 內(nèi)聯(lián)函數(shù)
2.1? 什么是內(nèi)聯(lián)函數(shù)
? ? ? 以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)調(diào)用建立棧幀的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
?如上圖,函數(shù)在調(diào)用時(shí)并沒有創(chuàng)建函數(shù)棧幀,而是直接在main函數(shù)內(nèi)部展開。
2.2? 內(nèi)聯(lián)函數(shù)的特性
- inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)用函數(shù)體替換函數(shù)調(diào)用
缺陷:可能會(huì)使目標(biāo)文件變大,
優(yōu)勢(shì):少了調(diào)用開銷,提高程序運(yùn)行效率.
?但也并不是所有的函數(shù)都要展開,內(nèi)聯(lián)函數(shù)展開的也只適用于較小的函數(shù)。
比如:
????????一個(gè)函數(shù)有100行代碼,被調(diào)用了1000次,每次都展開,那就是10w行代碼,產(chǎn)生的文件要多大,而如果是函數(shù)棧幀調(diào)用,每次調(diào)用都去同一塊空間調(diào)用函數(shù),也就只多了100行代碼。
- ?inline對(duì)于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建議:將函數(shù)規(guī)模較小(即函數(shù)不是很長(zhǎng),具體沒有準(zhǔn)確的說法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會(huì)忽略inline特性
?內(nèi)聯(lián)函數(shù)只是向編譯器發(fā)送一個(gè)請(qǐng)求,編譯器可以選擇忽略
- ?聲明和定義分離時(shí)不可以使用內(nèi)聯(lián)函數(shù)
?分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會(huì)找不到
內(nèi)聯(lián)函數(shù)在聲明和定義分離時(shí),直接調(diào)用會(huì)出現(xiàn)報(bào)錯(cuò),但是可以間接調(diào)用。
//fun.h
inline void fun()
{
cout << "hello ,world!" << endl;
}
//fun.c
void func()
{
fun();
}
//test.c
int main()
{
fun();
return 0;
}
?這種情況是可以正常調(diào)用的。
?3. auto關(guān)鍵字
?隨著程序越來越復(fù)雜,程序中用到的類型也越來越復(fù)雜,經(jīng)常體現(xiàn)在:
- 類型難于拼寫
- 含義不明確導(dǎo)致容易出錯(cuò)
?3.1 auto簡(jiǎn)介
????????使用auto修飾的變量,是具有自動(dòng)存儲(chǔ)器的局部變量 ,但是在日常中卻很少使用。
????????C++11中,標(biāo)準(zhǔn)委員會(huì)賦予了auto全新的含義即:auto不再是一個(gè)存儲(chǔ)類型指示符,而是作為一個(gè)新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。
?比如:
int Test()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = Test();
cout << typeid(b).name() << endl;//int
cout << typeid(c).name() << endl;//char
cout << typeid(d).name() << endl;//int
return 0;
}
auto會(huì)自動(dòng)讀取類型,并且使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化
注意:
????????使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來推導(dǎo)auto的實(shí)際類型。因此auto并非是一種“類型”的聲明,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編譯器會(huì)將auto替換為變量實(shí)際的類型
?3.2 auto使用規(guī)則
- ?與指針引用結(jié)合使用
?用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時(shí)則必須加&
int main()
{
int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;
cout << typeid(a).name() << endl;//int*
cout << typeid(b).name() << endl;//int*
cout << typeid(c).name() << endl;//int
return 0;
}
- 一行定義多個(gè)變量
????????當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器將會(huì)報(bào)錯(cuò),因?yàn)榫幾g
器實(shí)際只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
auto a = 1, b = 2;
auto c = 3, d = 4.0; ?// 該行代碼會(huì)編譯失敗,因?yàn)閏和d的初始化類型不同
?3.3 auto不能使用的場(chǎng)景
- ?auto不能作為函數(shù)返回類型
最新的C++語法是可以的,但是很不推薦,在日常應(yīng)用場(chǎng)景中一定不要這樣寫,在較大的項(xiàng)目中大多數(shù)都是多人合作的,如果你使用auto,那別人在調(diào)用你的函數(shù)接口時(shí)不知道返回類型很難搞,如果別人也用auto,這樣就會(huì)導(dǎo)致一系列連鎖,最后代碼越寫越 “ 屎山 ”,這就是典型的 “ 坑隊(duì)友 ”,要養(yǎng)成良好的代碼風(fēng)格。
- ?auto不能作為函數(shù)的參數(shù)
void TestAuto(auto a)//出現(xiàn)報(bào)錯(cuò),編譯器無法對(duì)a的實(shí)際類型進(jìn)行推導(dǎo)
{
}
int main()
{
TestAuto(2);
}
- auto不能直接聲明數(shù)組
?
4.? 基于范圍的for循環(huán)
?4.1 范圍for使用
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
//正常的for循環(huán)遍歷
for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
{
cout << arr[i] << ' ';
}
cout << endl;
//范圍for遍歷
for (int e : arr)
{
cout << e << ' ';//這里的e是數(shù)組值的拷貝,改變e無法改變數(shù)組的數(shù)據(jù)
}
return 0;
}
?????????對(duì)于一個(gè)有范圍的集合而言,由程序員來說明循環(huán)的范圍是多余的,有時(shí)候還會(huì)容易犯錯(cuò)誤。因此C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號(hào)由冒號(hào)“ :”分為兩部分:第一部分是范圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。
?注意:范圍for與普通循環(huán)類似,可以用continue來結(jié)束本次循環(huán),也可以用break來跳出整個(gè)循環(huán)。
?4.2 使用條件
- for循環(huán)迭代的范圍必須是確定的?
void TestFor(int array[])
{
??for(auto& e : array)
????cout<< e <<endl;
}
????????例如上述代碼,范圍并不明確。對(duì)于數(shù)組而言,就是數(shù)組中第一個(gè)元素和最后一個(gè)元素的范圍;對(duì)于類而言,應(yīng)該提供begin和end的方法,begin和end就是for循環(huán)迭代的范圍
5. C++空指針?
????????在C語言中我們常用的都是NULL來代表空指針,NULL實(shí)際是一個(gè)宏,在傳統(tǒng)的C頭文件(stddef.h)中,可以看到如下代碼:?
#ifndef NULL
#ifdef __cplusplus
#define NULL ?0
#else
#define NULL ?((void *)0)
#endif
#endif
可以看到,NULL可能被定義為字面常量0,或者被定義為無類型指針(void*)的常量。不論采取何
種定義,在使用空值的指針時(shí),都不可避免的會(huì)遇到一些麻煩?。我們可以使用C++代碼測(cè)試一下:
void f(int)
{
cout << "f(int)" << endl;
}
void f(int*)
{
cout << "f(int*)" << endl;
}
int main()
{
f(0); //f(int)
f(NULL); //f(int)
f((int*)NULL); //f(int*)
return 0;
}
?不難發(fā)現(xiàn)NULL在C++中被替換成了0,在C++98中,字面常量0既可以是一個(gè)整形數(shù)字,也可以是無類型的指針(void*)常量,但是編譯器默認(rèn)情況下將其看成是一個(gè)整形常量,如果要將其按照指針方式來使用,必須對(duì)其進(jìn)行強(qiáng)轉(zhuǎn)(void*)0。
為了保險(xiǎn)起見,C++引入nullptr,代表空指針,在后續(xù)表示指針空值時(shí)建議最好使用nullptr。文章來源:http://www.zghlxwxcb.cn/news/detail-715130.html
總結(jié)
? ? ? ? 到本期C++的一些入門簡(jiǎn)單語法已經(jīng)基本介紹完畢,后續(xù)將會(huì)繼續(xù)深入學(xué)習(xí)C++,以上便是本期全部?jī)?nèi)容?,最后,感謝閱讀!文章來源地址http://www.zghlxwxcb.cn/news/detail-715130.html
到了這里,關(guān)于【C++初階(三)】引用&內(nèi)聯(lián)函數(shù)&auto關(guān)鍵字的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!