欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中const用法小結(jié)

 更新時(shí)間:2016年04月12日 11:40:25   投稿:hebedich  
C++ const 允許指定一個(gè)語(yǔ)義約束,編譯器會(huì)強(qiáng)制實(shí)施這個(gè)約束,允許程序員告訴編譯器某值是保持不變的。如果在編程中確實(shí)有某個(gè)值保持不變,就應(yīng)該明確使用const,這樣可以獲得編譯器的幫助。

const在C++中使用十分廣泛,不同位置使用的意義也不盡相同,所以想寫篇文章對(duì)其做一個(gè)總結(jié)。

首先,明確const是“不變”這個(gè)基本意義,但是不變不意味著什么都不變,下面將會(huì)看到。

1. const與變量

基本原則:const變量(對(duì)象)不能被修改

const在變量中的引入和魔數(shù)有關(guān),所謂“魔數(shù)”指的是突然出現(xiàn)的一個(gè)常量值(也叫字面值常量)。

for(int i = 0; i < 512; i++)
{
// todo
}

上例中,512即為魔數(shù),512突然出現(xiàn)在循環(huán)中,令人不能得知其意義,所以引入const。

const int length = 512;
for(int i = 0; i < length; i++)
{
// todo
}

這樣就知道循環(huán)是在長(zhǎng)度范圍內(nèi)。

1.1 const修飾一個(gè)變量(或者說(shuō)對(duì)象),使其變成一個(gè)常量,表示該變量的值無(wú)法再被修改,正因?yàn)槿绱?,所以定義一個(gè)常量的時(shí)候,必須初始化。

1.2 const常量的作用域:

我們知道,在全局作用域內(nèi)聲明一個(gè)變量(此處特指非const修飾的變量),其作用于整個(gè)程序,在其他文件中也能被引用,原因是在全局作用域聲明一個(gè)變量,默認(rèn)是extern修飾的。

在全局作用域內(nèi)聲明一個(gè)const變量,默認(rèn)不是extern修飾,所以其只能作用于本文件內(nèi),若要在其他文件中訪問(wèn),需要顯式聲明為extern

2. const與引用

基本原則:const引用是指向const變量(對(duì)象)的引用

const int ival = 1024;
const int &refVal = ival;

2.1 const引用可以指向一個(gè)相關(guān)類型(不是本類型)的const變量

double dval = 3.14;
const int &refVal = dval;

編譯器將double轉(zhuǎn)換成一個(gè)臨時(shí)的int對(duì)象,然后讓const引用綁定到這個(gè)臨時(shí)對(duì)象,所以改變dval的值不會(huì)改變r(jià)efVal,也就是說(shuō)dval仍然是非const變量,refVal仍然是常量引用。

primer第四版是上面的說(shuō)法,但我在VS2012中,const也可以指向一個(gè)本類型的非const變量,查找資料的原因大概是滿足reference-campatible條件。

理論上,我們應(yīng)該嚴(yán)格遵守,常量引用指向常量對(duì)象,非常量引用指向非常量對(duì)象,避免出錯(cuò)。

3. const與指針

const與指針的關(guān)系分為兩種:const修飾的指針和指向const對(duì)象的指針,二者const的位置不相同

3.1 指向const對(duì)象的指針(const位于指針?lè)?hào)*前面)

對(duì)于一個(gè)const對(duì)象,必須用一個(gè)指向const的指針來(lái)指向它。原因在于,const修飾使得對(duì)象無(wú)法被改變,而指針如果不是指向const的指針,則可以通過(guò)指針來(lái)修改對(duì)象,這是不被允許的。

const int ival = 1;
const int *ptrVal = &ival;

反過(guò)來(lái),對(duì)于一個(gè)指向const對(duì)象的指針,可以指向任意一個(gè)對(duì)象,這個(gè)該怎么理解呢?我們首先看看指針賦值的過(guò)程:

int *ptr = &val;

將val的地址賦值給ptr,因?yàn)橘x值的只是地址,所以不知道ptr所指向的對(duì)象是否為const。

如果我們把一個(gè)地址賦值給一個(gè)指向const的指針,那么指針認(rèn)為這是一個(gè)const的對(duì)象,也就是說(shuō),ptr指針指向了一個(gè)“自認(rèn)為”是const的對(duì)象。

int ival = 1;
const int *ptrVal = &ival;

上面的程序是正確的,我們需要明確,ival是非const變量,所以我們可以通過(guò)給ival賦值更改ival的值。ptrVal指向了一個(gè)自認(rèn)為是const的對(duì)象,所以我們無(wú)法通過(guò)*ptrVal來(lái)更改ival的值。

3.2 const修飾的指針(const位于指針?lè)?hào)*后面)

int *const ptr;

上式聲明了一個(gè)const類型的指針,表示的意思是指針本身是一個(gè)常量,不能被修改。

如何理解?指針本身的值是一個(gè)地址,如果指針本身是一個(gè)常量,則這個(gè)地址值不能被修改,也就是說(shuō)指針只能指向這個(gè)地址,不能指向其他地方。但指針?biāo)赶虻牡刂返膬?nèi)容不屬于指針本身的值,所以其所指向的內(nèi)容可以改變。

int ival = 1;
int *const ptr = &ival;
*ptr = 2;          // ok
int ivalTwo = 11;
ptr = &ivalTwo       // error

綜上,可以定義一個(gè)指向const對(duì)象的const指針

const int *const ptr = &ival;

3.3 typedef中易出錯(cuò)的const指針

typedef string *ptr;
const ptr s_ptr;

上式不能直接替換理解為const string *s_prt; 從而認(rèn)為s_ptr是一個(gè)指向const string的指針。
首先,ptr是一個(gè)指針,const修飾的是一個(gè)指針,所以應(yīng)該是string *const s_ptr; s_ptr是一個(gè)指向string的const指針。

4. const與數(shù)組

const與數(shù)組的點(diǎn)在于const在定義時(shí)必須初始化這個(gè)原則,所以使用動(dòng)態(tài)分配數(shù)組時(shí),如果數(shù)組存儲(chǔ)的是const類型的對(duì)象,必須進(jìn)行初始化(使用初始化符號(hào)())。

5. const與函數(shù)返回值

修飾函數(shù)的返回值,用于返回一個(gè)常量。

const int foo();

5.1 返回通過(guò)值傳遞

如果函數(shù)返回時(shí)采用值傳遞,比如返回一個(gè)int類型,那么函數(shù)會(huì)把返回的值(比如47)復(fù)制到外部臨時(shí)存儲(chǔ)單元中(產(chǎn)生臨時(shí)副本),所以加const修飾毫無(wú)意義

int foo();
const int foo();

二者完全相同。需要注意的是,值傳遞產(chǎn)生臨時(shí)副本,效率低(下面const與函數(shù)參數(shù)有講),所以通常采用引用傳遞來(lái)返回。

5.2 返回通過(guò)引用傳遞(并不多見)

如果返回值不是內(nèi)部類型,通常使用引用傳遞來(lái)返回結(jié)果,因?yàn)橐脗鬟f的是本身,不需要產(chǎn)生臨時(shí)副本。但需要注意的是,此時(shí)僅僅返回一個(gè)別名。

ClassType &foo();
const ClassType &foo();

const修飾的返回引用值,表示函數(shù)調(diào)用的結(jié)果只能賦值給一個(gè)同類型的const引用。

5.3 返回通過(guò)指針傳遞

const ClassType *foo();

表示函數(shù)返回一個(gè)ClassType類型的指針,這個(gè)指針指向一個(gè)const對(duì)象,指針?biāo)傅膬?nèi)容不能被修改,所以函數(shù)的返回值只能賦值給指向一個(gè)const的同類型的指針。

const ClassType *ptr = foo();  //ok
ClassType *ptr = foo();     //error

6. const與函數(shù)參數(shù)

首先需要明確,const修飾的目的就在于保護(hù)所修飾的內(nèi)容不被改變。
在C++中,函數(shù)參數(shù)分為值傳遞,指針傳遞和引用傳遞。

6.1 值傳遞

值傳遞在函數(shù)調(diào)用時(shí)產(chǎn)生一個(gè)臨時(shí)副本,函數(shù)中對(duì)傳入?yún)?shù)的修改和操作是對(duì)副本的操作,不改變實(shí)參本身的值,所以無(wú)需const來(lái)保護(hù)。
值傳遞的保護(hù)很好,但值傳遞存在缺點(diǎn),需要產(chǎn)生臨時(shí)副本,如果傳入的是對(duì)象,那么需要進(jìn)行構(gòu)造、復(fù)制、和析構(gòu)等操作,效率不高。這時(shí)候可以考慮引用傳遞

void foo1(int x);
void foo2(ClassType instance);     //開銷較大

下面這種保護(hù)無(wú)意義:

void foo1(const int x);
void foo2(const ClassType instance);  

6.2 引用傳遞

通過(guò)傳入實(shí)參的引用,降低開銷。因?yàn)橐眉幢旧?,不需要去產(chǎn)生一個(gè)臨時(shí)副本。

void foo1(int &x);
void foo2(ClassType &ref);

對(duì)于上述兩個(gè)函數(shù),函數(shù)調(diào)用和值傳遞的形式完全一樣,不同的是函數(shù)內(nèi)部得到的x和ref是調(diào)用傳入實(shí)參的引用。也正因?yàn)槿绱耍每梢酝ㄟ^(guò)函數(shù)改變傳入的參數(shù)來(lái)改變實(shí)參。這對(duì)與實(shí)參來(lái)說(shuō),比較危險(xiǎn),這時(shí)候需要通過(guò)const修飾來(lái)保護(hù)傳入的引用不被修改。

void foo1(const int &x);
void foo2(const ClassType &ref);

通常來(lái)說(shuō),對(duì)于基本內(nèi)部類型,不存在對(duì)象的構(gòu)造等操作,所以下面兩種保護(hù)參數(shù)不被修改的方式效率基本一樣。

void foo1(int x);
void foo1(const int &x);

6.3 指針傳遞

指針傳遞在保護(hù)參數(shù)不被修改上和引用傳遞是一樣的,指針傳遞還有一個(gè)功能是可以擴(kuò)大接收參數(shù)的范圍:

void foo1(const ClassType *ptr);

結(jié)合上面const與指針,我們知道,ptr指向一個(gè)自認(rèn)為是const類型的對(duì)象,所以!傳入的對(duì)象不一定是const修飾的對(duì)象,可以是const對(duì)象,也可以非const對(duì)象。反過(guò)來(lái),如果沒(méi)有const修飾函數(shù)的形參,則只能傳入非const對(duì)象。

需要明確,無(wú)論傳入的是否是const對(duì)象,都無(wú)法通過(guò)指針來(lái)修改這個(gè)對(duì)象,這和上面指針與const的關(guān)系是一致的。

最后需要知道:const只能修飾一個(gè)輸入?yún)?shù),如果是輸出參數(shù),無(wú)論是引用傳遞還是指針傳遞,都不能使用const來(lái)修飾

7. const與類的數(shù)據(jù)成員

const修飾的數(shù)據(jù)成員不能在構(gòu)造函數(shù)中進(jìn)行初始化,只能使用成員初始化列表進(jìn)行初始化。
我的理解是,因?yàn)樵跇?gòu)造函數(shù)執(zhí)行之前,使用成員初始化列表對(duì)數(shù)據(jù)成員進(jìn)行初始化,如果在構(gòu)造函數(shù)中對(duì)數(shù)據(jù)成員進(jìn)行初始化,相當(dāng)于對(duì)const進(jìn)行二次賦值,這是不被允許的。

之所以這么理解,可以參照類中引用類型的初始化,也是必須在初始化列表中進(jìn)行初始化,因?yàn)橐妙愋鸵彩窃诙x的時(shí)候必須初始化,要求和const一樣,所以二者都只能使用成員初始化列表來(lái)進(jìn)行初始化。

8. const與類的成員函數(shù)

const成員函數(shù)中,const位于函數(shù)的參數(shù)列表后面(函數(shù)聲明前面表示函數(shù)的返回值是一個(gè)常量)

const修飾的成員函數(shù)表示成員函數(shù)是一個(gè)只讀的作用,不改變成員變量。
const成員函數(shù)真正的含義在于,const其實(shí)修飾的成員函數(shù)的是隱含參數(shù)this指針,也就是說(shuō)傳入的是const ClassType *this,因?yàn)閠his指向一個(gè)const對(duì)象,所以不能修改。

因?yàn)閠his是指向?qū)ο蟮闹羔?,所以我們需要再次結(jié)合const與指針的知識(shí):

(1)const修飾了this,得到const ClassType *this,this指向一個(gè)“自認(rèn)為”是const的對(duì)象(也就是本身),所以任何對(duì)象(const或者非const)都可以調(diào)用一個(gè)const成員函數(shù),因?yàn)閭魅氲闹羔樁及炎陨磉@個(gè)對(duì)象看作是const對(duì)象,所以不能被修改。
(2)對(duì)于一個(gè)const對(duì)象,當(dāng)其調(diào)用成員函數(shù)的時(shí)候,默認(rèn)都傳入this指針參數(shù),因?yàn)閠his此時(shí)指向一個(gè)const對(duì)象(本身),所以相當(dāng)于成員函數(shù)被const修飾,成員函數(shù)是一個(gè)const成員函數(shù),所以反過(guò)來(lái)說(shuō),const對(duì)象只能調(diào)用const成員函數(shù),因?yàn)榉莄onst修飾的成員函數(shù),this指針不是指向const對(duì)象。
(3)在8.2的基本上,進(jìn)一步,每個(gè)成員函數(shù)都可以調(diào)用其他成員函數(shù),每個(gè)成員函數(shù)都傳入this指針,所以成員函數(shù)相互調(diào)用必須保持this指針的一致性,所以const成員函數(shù)只能調(diào)用const成員函數(shù),因?yàn)槎邆魅氲膖his指針都是const修飾的。對(duì)于非const成員函數(shù),其傳入非const修飾的this指針,所以不能被調(diào)用。

搞清楚const真正的含義就明白了,一定要保持const成員函數(shù)傳入的是const指針這個(gè)意識(shí),對(duì)象調(diào)用就需要看對(duì)象(本身,指針,引用)是否是const。

相關(guān)文章

  • C++類的構(gòu)造與析構(gòu)特點(diǎn)及作用詳解

    C++類的構(gòu)造與析構(gòu)特點(diǎn)及作用詳解

    本文章將會(huì)可能會(huì)涉及到匯編的知識(shí),不過(guò)沒(méi)有關(guān)系,我會(huì)講的盡量通俗易懂;另外本篇文章開始前,建議了解下什么是函數(shù)重載,這個(gè)概念很簡(jiǎn)單的--有相同的函數(shù)名,但參數(shù)列表不相同的函數(shù),就是函數(shù)重載
    2022-10-10
  • C語(yǔ)言strlen和sizeof在數(shù)組中的使用詳解

    C語(yǔ)言strlen和sizeof在數(shù)組中的使用詳解

    對(duì)于 strlen 和 sizeof,相信不少程序員會(huì)混淆其功能。雖然從表面上看它們都可以求字符串的長(zhǎng)度,但二者卻存在著許多不同之處及本質(zhì)區(qū)別
    2021-10-10
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)項(xiàng)目

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Lambda表達(dá)式里面修改外部變量問(wèn)題

    Lambda表達(dá)式里面修改外部變量問(wèn)題

    這篇文章主要介紹了Lambda表達(dá)式里面修改外部變量的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 數(shù)據(jù)結(jié)構(gòu)之矩陣行列和相等的實(shí)例

    數(shù)據(jù)結(jié)構(gòu)之矩陣行列和相等的實(shí)例

    這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之矩陣行列和相等的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • 利用C++11原子量如何實(shí)現(xiàn)自旋鎖詳解

    利用C++11原子量如何實(shí)現(xiàn)自旋鎖詳解

    當(dāng)自旋鎖嘗試獲取鎖時(shí)以忙等待(busy waiting)的形式不斷地循環(huán)檢查鎖是否可用,下面這篇文章主要給大家介紹了關(guān)于利用C++11原子量如何實(shí)現(xiàn)自旋鎖的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-06-06
  • c++中inline的用法分析

    c++中inline的用法分析

    本篇文章是對(duì)c++中inline的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++基礎(chǔ)入門教程(二):數(shù)據(jù)、變量、宏等

    C++基礎(chǔ)入門教程(二):數(shù)據(jù)、變量、宏等

    這篇文章主要介紹了C++基礎(chǔ)入門教程(二):數(shù)據(jù)、變量、宏等,本文講解了變量初始化、宏定義、三種進(jìn)制數(shù)的表示、const初探、auto聲明等內(nèi)容,需要的朋友可以參考下
    2014-11-11
  • 基于Matlab實(shí)現(xiàn)抖音小游戲蘋果蛇

    基于Matlab實(shí)現(xiàn)抖音小游戲蘋果蛇

    最近抖音上蘋果蛇小游戲大火,為了證明MATLAB無(wú)所不能,咋能不跟風(fēng)做一個(gè)?文中詳細(xì)講解了游戲的實(shí)現(xiàn)步驟,感興趣的小伙伴可以嘗試一下
    2022-06-06
  • 一篇文章帶你了解C++面向?qū)ο缶幊?-繼承

    一篇文章帶你了解C++面向?qū)ο缶幊?-繼承

    這篇文章主要介紹了解析C++面對(duì)象編程--繼承的運(yùn)用,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下,希望能夠給你帶來(lái)幫助
    2021-08-08

最新評(píng)論