[C/C++]const限定符總結

const限定符

const是一種限定符,被const所限定的變量其值不能夠被改變。c++

const的初始化

因爲const一旦建立其值就不可以被改變,因此咱們必須對其進行初始化程序員

const int a;//錯誤,const變量必須進行初始化!
const int b=10;//正確,編譯時初始化
const int c=get_size();//正確,運行時初始化

相同類型的變量相互初始化時,不論變量是否被const限定咱們均可以進行隨意的相互拷貝。由於在拷貝過程當中咱們只會用到等式右邊變量的右值屬性,無須在乎其是否能夠改變。指針

int m = 5;
const int n = m;
int j = n;

const與指針

頂層const與底層const

對於指針來講,因爲其指向另外一片內存的特色,有三種不一樣的const狀況,即:code

  1. 指向常量的指針(const int *)
  2. 常量指針(int * const)
  3. 指向常量的常量指針(const int *const)

咱們通常稱符合第一種狀況的爲具備底層const屬性。
符合第二種狀況的爲具備頂層const屬性。
第三種狀況兼而有之。對象

關於帶有const的指針的相互賦值(或者初始化)問題

  1. 頂層const並不會影響變量間的相互拷貝(緣由是頂層const只保證自身的值不會改變,const沒有改變自身的變量類型,在拷貝時只是使用該類型的右值)。
  2. 若是等號右邊是底層const,那麼等號左邊必須保證爲相同的底層const(或者等號右邊的類型能夠轉換成等號左邊的類型),否者表達式沒法經過編譯。

關於底層與頂層const的一些想法

const的底層與頂層屬性彷佛只在指針上存在。可是c++primer中有這樣的代碼和註釋:內存

const int ci=1,&cr=ci;
auto b=ci;//b是一個整數(ci的頂層const特性被忽略掉了)
auto c=cr;//c是一個整數(cr是ci的別名,ci自己是一個頂層const)

這段代碼是爲了說明auto說明符通常會忽略掉頂層const的特性,在註釋中明確寫着ci自己是一個頂層const
這也與個人見解一致,底層與頂層const實際上並非指針所特有的,只要是不能改變對象自身的對象都具備頂層const,而不能改變本身所指向的對象的對象都具備底層const。
從這個角度看,引用實際上自帶頂層const。ci

底層const的隱式轉換

上面提到,只有在等號右邊和等號左邊的類型具備相同的底層const屬性,才能夠進行賦值或者初始化。
然而有些時候等號右邊可能並不具備和等號左邊一致的底層const卻依然能夠成立,這是由於等號右邊的類型發生了隱式轉換從而具備了和等號左邊類型相同底層const屬性。
例如:get

int i=5;
int *p=&i;
const int *cp=p//int*隱式轉換稱爲了const int*

爲何int 轉換成const int 被設定爲合法的呢,由於在將int 轉換爲const int 的過程當中用戶的權限變小了,在這一轉換過程當中並不會使程序變得不可靠。
由此咱們能夠得知非底層const的指針是能夠經過隱式轉換轉變成底層const的。編譯器

const與引用

能夠把引用綁定在const的變量上,稱爲const的引用,對常量的引用。
與普通的引用不一樣的是,對常量的引用不能被用做修改它所綁定的對象編譯

const int ci=5;
const int &r=ci;
r=6//錯誤不能夠經過常引用來修改值
int &r2=ci//錯誤,試圖讓一個很是量引用指向一個常量對象。

const引用的初始化

咱們知道對於引用來講初始化時必定要用一個對象初始化,且該對象的類型須要與之匹配。
可是const的引用是個例外,在初始化常量引用時容許用任意表達式做爲初始值,只要該表達式的結果能轉換成引用的類型便可,甚至容許爲一個常量引用綁定很是量的對象、字面值或者是表達式。

int i=42;
const int &r1=i;//容許將const int&綁定到一個普通int對象上
const int &r2=3.14;//正確:r2是一個常量引用
const int &r3=r1*2;//正確:r3是一個常量引用
int &r4 =r1*2;//錯誤,很是量引用不能用表達式初始化。

C++primer中給出了能夠這麼作的緣由:

要想理解這種例外狀況的緣由,最簡單的方法是弄清楚當一個常量引用被綁定到另一種類型上都時到底發生了什麼:

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

此處ri引用了一個int型的數。對ri的操做應該是整數運算,但dval倒是一個雙精度浮點數而非整數。所以爲了確保讓ri綁定一個整數,編譯器把上述代碼變成了以下形式:

const int temp=dval;//由雙精度浮點數生成一個臨時的整型常量
const int &ri=temp;//讓ri綁定這個臨時量

在這種狀況下,ri綁定了一個臨時量對象。所謂臨時量對象就是當編譯器須要一個空間來暫存表達式的求值結果時臨時建立的一個未命名的對象。C++程序員們經常把臨時量對象簡稱爲臨時量。

const與auto類型說明符

auto類型說明符是C++11中新引入的類型說明符,能夠自動推斷類型。
編譯器推斷出來的auto類型有時候和初始值的類型並不徹底同樣,編譯器會適當的改變結果類型使其更符合初始化規則。
auto在推斷帶有const的對象時,編譯器通常會忽略掉頂層const,同時底層const則會保留下來。
另外對於引用因爲引用沒有真正的實體,因此若是用一個引用來初始化auto類型時,auto實際上爲引用所指向的對象的類型,而非引用,若是要說明其爲引用類型,須要使用auto&。

const int ci=i,&cr=ci;
auto b=ci;//b是一個整數(ci的頂層const特性被忽略掉了)
auto c=cr;//c是一個整數(cr是ci的別名,ci自己是一個頂層const)
auto d=&i;//d是一個整型指針(整數的地址就是指向整數的指針)
auto e=&ci;//e是一個指向整數常量的指針(對常量對象取地址是一種底層const)

若是但願推斷出的auto類型是一個頂層const,須要明確指出:

const auto f=ci;//ci的推演類型爲int,f是const int。
相關文章
相關標籤/搜索