網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
C++類與對(duì)象深入之引用與內(nèi)聯(lián)函數(shù)與auto關(guān)鍵字及for循環(huán)詳解_C 語(yǔ)言
作者:Rookiep ? 更新時(shí)間: 2022-08-03 編程語(yǔ)言一:引用
1.1:概念
引用不是定義一個(gè)新的變量,而是給已經(jīng)存在的變量取一個(gè)別名。注意:編譯器不會(huì)給引用變量開辟內(nèi)存空間,他和他的引用變量共用同一塊內(nèi)存空間。
類型& 引用變量名(對(duì)象名) = 引用實(shí)體。
1.2:引用特性
1. 引用在定義時(shí)必須初始化
2. 一個(gè)變量可以有多個(gè)引用
3. 引用一旦引用一個(gè)實(shí)體,也就不能引用其他實(shí)體
通俗的講就是:我們?nèi)⊥馓?hào),肯定是對(duì)一個(gè)對(duì)象取外號(hào),不可能是這空氣取外號(hào),而且也可以給同一個(gè)人取多個(gè)外號(hào),但是同一個(gè)外號(hào)我們就不要給多個(gè)人取了,那樣就亂套了,就不知道叫的是誰(shuí)了。
1.3:常引用
原則:對(duì)原引用變量,權(quán)限只能縮小,不能放大。
int main(){
const int x = 20;
//int& y = x; // 放大
const int& y = x; // 不變
int c = 30;
const int& d = c; // 縮小
//cout << d << endl;
system("pause");
return 0;
}
對(duì)常變量取別名時(shí),要加const;
const int & b = 10;
注意:當(dāng)引用類型和引用實(shí)體不是同一類型時(shí),如:
double a = 3.14;
//int &ra = a; //該編譯語(yǔ)句會(huì)報(bào)錯(cuò),因?yàn)轭愋筒煌?
const int & ra = a;
//加上const就可以了。
我們可以這么理解,當(dāng)浮點(diǎn)型轉(zhuǎn)換整型數(shù)據(jù)時(shí),其中我們?cè)贑語(yǔ)言學(xué)過會(huì)發(fā)生隱式類型轉(zhuǎn)換,在轉(zhuǎn)換的時(shí)候會(huì)產(chǎn)生一個(gè)臨時(shí)變量,這個(gè)臨時(shí)變量具有常性,不可以被修改,如果不加const,那么權(quán)限被放大,所以需要加上const保證他的權(quán)限不變。
其實(shí)現(xiàn)在ra的地址已經(jīng)不再是原變量a的地址了,是其中臨時(shí)變量的地址。
1.4:使用場(chǎng)景
做參數(shù):
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
void Swap(double& x, double& y)
{
double tmp = x;
x = y;
y = tmp;
}
做返回值 下面我們先看兩個(gè)代碼
int & Add(int a, int b){
static int c = a + b;
return c;
}
int main(){
int & ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
system("pause");
return 0;
}
Add(1, 2) is :3
//請(qǐng)按任意鍵繼續(xù). . .?
int & Add(int a, int b){
int c = a + b;
return c;
}
int main(){
int & ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
system("pause");
return 0;
}
Add(1, 2) is :7
//請(qǐng)按任意鍵繼續(xù). . .
都一個(gè)結(jié)果是3,第二個(gè)結(jié)果是7,為什么會(huì)這樣呢?
我們知道在函數(shù)返回值時(shí)實(shí)際是產(chǎn)生一個(gè)臨時(shí)變量,若傳值返回,那么實(shí)際是發(fā)生了拷貝,若引用返回,那么其實(shí)是給這個(gè)臨時(shí)變量取了別名,返回了這個(gè)臨時(shí)變量的別名。 對(duì)于靜態(tài)變量c的作用域不變,但是生命周期變長(zhǎng),在Add函數(shù)返回時(shí),出了作用域,返還對(duì)象并沒有還給系統(tǒng),所以此時(shí)ret一直是第一次調(diào)用Add函數(shù)時(shí)產(chǎn)生的臨時(shí)變量的別名,所以ret的結(jié)果是3。
1.5:引用和指針的區(qū)別
在語(yǔ)法概念上,引用就是一個(gè)別名,沒有開辟獨(dú)立的空間存儲(chǔ),和其引用實(shí)體共用同一塊實(shí)體。
int main(){
int a = 10;
int & ra = a;
cout << "&a = " << &a << endl;
cout << "&ra = " << &ra << endl;
system("pause");
return 0;
}
&a = 0137F8D8
&ra = 0137F8D8
請(qǐng)按任意鍵繼續(xù). . .
由代碼結(jié)果可看是同一塊地址。
在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂绞絹?lái)實(shí)現(xiàn)的。
引用和指針的不同點(diǎn):
- 引用在定義時(shí)必須初始化,指針沒有要求。
- 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時(shí)候指向任何一個(gè)同類型實(shí)體。
- 沒有NULL引用,但是有NULL指針。
- sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個(gè)數(shù)。
- 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類型的大小。
- 有多級(jí)指針,但沒有多級(jí)引用。
- 訪問實(shí)體不同,指針需要顯式解引用,引用編譯器自己處理。
- 引用比指針使用起來(lái)更加安全。
二:內(nèi)聯(lián)函數(shù)
2.1:概念
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),用于解決C語(yǔ)言中宏函數(shù)難懂易錯(cuò)的缺陷。在編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)壓棧的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
如果在上述函數(shù)前增加inline關(guān)鍵字,將其改成內(nèi)聯(lián)函數(shù),那么在編譯期間編譯器會(huì)用函數(shù)體(展開)替換函數(shù)的調(diào)用。
查看方式:
在Release模式下,查看編譯器生成的匯編代碼中是否有call Add
在Debug模式下,需要對(duì)編譯器進(jìn)行設(shè)置,否則也不會(huì)展開。
如VS2013版本設(shè)置:
右擊項(xiàng)目名稱——>屬性:
2.2:特性
- inline是一種以空間換取時(shí)間的做法,利用直接展開函數(shù)省去調(diào)用函數(shù)的開銷。所以對(duì)于代碼很長(zhǎng)或者有循環(huán)/遞歸的函數(shù)不方便使用作為內(nèi)聯(lián)函數(shù)。
- inline對(duì)于編譯器而言只是一個(gè)建議,編譯器會(huì)自動(dòng)優(yōu)化,如果定義的inline的函數(shù)體內(nèi)有循環(huán)/遞歸等,編譯器優(yōu)化時(shí)會(huì)忽略掉內(nèi)聯(lián)。
- inline不建議聲明和定義分開,分開會(huì)導(dǎo)致鏈接錯(cuò)誤,因?yàn)閕nline被展開,就沒有函數(shù)地址了,如果分開了,鏈接的時(shí)候就找不到了。
2.3:面試題
宏的優(yōu)點(diǎn)?
- 增強(qiáng)代碼的復(fù)用性
- 提高性能
缺點(diǎn):
- 不方便調(diào)試,因?yàn)榫幾g階段進(jìn)行了宏替換。
- 導(dǎo)致代碼可讀性差,可維護(hù)性差,容易誤用。
- 沒有類型安全檢查。
C++哪些技術(shù)可以替代宏?
- 常量定義,換用const。
- 函數(shù)定義,換用內(nèi)聯(lián)函數(shù)。
三:auto關(guān)鍵字
3.1:auto簡(jiǎn)介
我們?cè)趯W(xué)習(xí)C語(yǔ)言的時(shí)候就見過auto,當(dāng)時(shí)認(rèn)為使用auto修飾的變量是具有自動(dòng)存儲(chǔ)器的局部變量,但我們幾乎沒有使用。
在C++11中,標(biāo)準(zhǔn)委員會(huì)賦予了auto全新的含義:auto不再是一個(gè)存儲(chǔ)類型標(biāo)識(shí)符,而是作為一個(gè)新的類型指示符來(lái)指示編譯器,auto聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得。
int TestAuto()
{
return 10;
}
int main()
{
const int a = 10;
auto b = &a;
auto c = 'a';
auto d = TestAuto();
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
return 0;
}
這里我們看打印的結(jié)果是:
int const *
char
int
請(qǐng)按任意鍵繼續(xù). . .
可見auto關(guān)鍵字可以自動(dòng)識(shí)別變量的類型。這里**typeid(b).name()**可返回變量類型的字符串。
【注意】:使用auto關(guān)鍵字定義變量時(shí),必須對(duì)其初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來(lái)推導(dǎo)auto的實(shí)際類型。因此auto并非是一種類型的聲明,而是一種類型聲明時(shí)的占位符,編譯器在編譯期間會(huì)將auto替換為變量實(shí)際類型。
3.2:auto使用細(xì)則
auto與指針和引用結(jié)合使用
用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別,但是用auto聲明引用類型時(shí)則必須加&。
int main()
{
int x = 10, y = 20;
auto a = &x;
auto* b = &x;
auto& c = x;
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
*a = 20;
*b = 30;
c = 40;
system("pause");
return 0;
}
int *
int *
int
請(qǐng)按任意鍵繼續(xù). . .
看這里a和b的類型都是int * ,所以用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別。
在同一行定義多個(gè)變量當(dāng)在同一行聲明多個(gè)變量的時(shí)候,這些變量必須是同一類型的,否則編譯器會(huì)出錯(cuò),因?yàn)榫幾g器實(shí)際只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來(lái)的類型定義其他變量。
注意看d下面編譯器報(bào)錯(cuò)了,因?yàn)閏和d的初始化表達(dá)式類型不同。
3.3:auto不能推導(dǎo)的場(chǎng)景
1:auto不可以作為函數(shù)形參
因?yàn)樵谛螀⑻幨褂胊uto,編譯器無(wú)法對(duì)a的實(shí)際類型進(jìn)行推導(dǎo)。
2:auto不可以用來(lái)聲明數(shù)組。
四:基于范圍的for循環(huán)
4.1:范圍for循環(huán)的語(yǔ)法
對(duì)于一個(gè)有范圍的集合而言,在C++98中由程序員來(lái)說明循環(huán)的范圍是多余的,有時(shí)候還容易犯錯(cuò)。因此在C++11中引入基于范圍的for循環(huán)。for循環(huán)后的括號(hào)由冒號(hào)“:”分為兩部分。第一部分是范圍內(nèi)用于迭代的變量,第二部分則是表示被迭代的范圍。
int main(){
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < sizeof(array) / sizeof(int); ++i){
array[i] *= 2;
}
for (int i = 0; i < sizeof(array) / sizeof(int); ++i){
cout << array[i] << " ";
}
cout << endl;
// 范圍for
// 依次自動(dòng)取array中的數(shù)據(jù),賦值給e,自動(dòng)判斷結(jié)束
for (auto& e : array){
e /= 2;
}
for (auto x : array){
cout << x << " ";
}
cout << endl;
system("pause");
return 0;
}
2 4 6 8 10 12 14 16 18
1 2 3 4 5 6 7 8 9
請(qǐng)按任意鍵繼續(xù). . .
對(duì)于語(yǔ)句auto x : array意思是依次自動(dòng)取array中的數(shù)據(jù),賦值給e,所以相當(dāng)于e是array中的拷貝,既然是拷貝,也就不能對(duì)array中的數(shù)據(jù)產(chǎn)生影響。對(duì)要改變array中數(shù)據(jù),需要利用引用,正如代碼中auto& e : array。
4.2:范圍for循環(huán)的使用條件
for循環(huán)迭代的范圍必須是確定的。
下面給出一個(gè)錯(cuò)誤代碼示例:
void TestFor(int array[])
{
for (auto& e : array)
cout << e << endl;
}
因?yàn)槲覀冎溃瘮?shù)傳參,形參相對(duì)于實(shí)參發(fā)生降維,形參array是一個(gè)整型指針,所以這里for循環(huán)的迭代范圍是不確定的。
原文鏈接:https://blog.csdn.net/qq_43727529/article/details/124709088
相關(guān)推薦
- 2022-06-23 C語(yǔ)言實(shí)現(xiàn)鏈表與文件存取的示例代碼_C 語(yǔ)言
- 2023-01-17 關(guān)于最大池化層和平均池化層圖解_python
- 2022-06-19 python繪制餅圖和直方圖的方法_python
- 2022-10-01 Pycharm安裝scrapy及初始化爬蟲項(xiàng)目的完整步驟_python
- 2022-09-25 Shiro和SpringSecurity
- 2022-09-08 pytorch關(guān)于Tensor的數(shù)據(jù)類型說明_python
- 2023-03-29 golang?channel讀取數(shù)據(jù)的幾種情況_Golang
- 2022-04-21 catalina.out 和 catalina.log 的區(qū)別和用途
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支