一.不同标準下const特性
c語言所用的标準為C89;c++所用的标準為C++99,在這兩個标準下,對const特性有不同的定義.
c89:
1.const為一個常變量,編譯器将其當成一個變量進行編譯。唯一與變量不同的地方是:不能将const作為左值來使用。我們知道,改變一個值的方式有很多中,const不能作為左值,但通過指針偏移通路const變量,依然可以改變const所修飾的變量的值。
2.const所修飾的變量不一定要初始化。
c++99:
1.const修飾的常量必須初始化。
2.并且可以作為數組名,數組下标來使用。
3.對該類變量編譯時,以常量的方式進行編譯,但在編譯過程中,将用到常量名字的地方,全部替換成常量的值(這裡有一個條件,是用到常量值的地方,常量名字被替換成常量的值,其他地方,如引用這個常量時,并不對該常量進行替換)
4.const修飾的常量可以被改變值,但其輸出時,會被替換成初始值。
5.當const的初始值為一個變量時,就退化為常變量來使用(int b=0;const int a=b)
const特性:
1.不能作為左值。
2.不能間接的修改常量的值,會導緻常量位址的洩漏(同引用)。
引用:兩種作用,1是取位址,2是引用,區分其是取位址還是引用,看引用符号前面有沒有類型,有類型則是引用,否則就是取位址,這也是引用一經初始化就不能更改的原因(另一個原因是,引用符号在編譯的過程中會立馬被解析成解引用來使用)。引用隻有在c++11标準下有二級引用,其他目前都隻用到一級。
另外引用有一下幾個特點:1.必須初始化。2.不參與類型。3.對于記憶體位址不可洩漏的變量和立即數使用常引用。
引用和指針的相同點:在彙編過程中是一模一樣的,都是兩句代碼,先從記憶體中取位址,再給取到的位址指派。
引用和指針的不同點:1.定義的方式是不同的。
2.指針需要自己解引用,而引用在彙編時編譯器對其自動解引用,可以說比指針安全友善了許多。
注意點:引用變量作為變量也需要占用空間,一般和指針類型占用的空間大小相同。
對指針解引用取得的是指針自己的位址,(int* p=&a,&p?)
對引用解引用取得是引用所引用變量的位址。(int &p=a,&p?)
上面的兩個&p是不同的。
const和一級指針的結合點
對于const,編譯器需要保證const修飾的值不能被直接或間接的改變。如果打算将一個常量的位址放到普通的指針中去,那就會發生錯誤。
這裡需要注意的點:
int const *p;
const int *P;
int * const p;
const int * const p;
這四個p變量的特點有什麼不同?
1.第一個p和第二個p是一樣的,const修飾的是int型,是以p自身可以變,但p所指向的數字不能變。
2.第三個p,自己不可以變,但其所引用的數字可以變。
3.最後一個是兩個都可以變。
這裡的訣竅是:檢視離const最近的類型,那就是const所修飾的變量。const所修飾的變量永遠都适用上面的兩句話。
插入一個思考題:
int a=10;
int *p=&a;
const int **q=&p;
觀察這三句話,想想第三句為什麼編譯出錯,該怎麼解決。
這裡引用和指針的用法是一樣的。
還記得函數重載需要的條件嗎?
函數名相同,參數不同就可以構成重載(前提是重載函數是在同一個作用域下,本質原因是它們的符号産生是由函數名加參數清單構成的),在這裡,參數不同主要是類型不同。const的參與是否會改變類型,這是一個重要的問題,如何看const是否參與類型?看const的右邊是否有*,如果有那麼const參與類型,如果沒有,那麼const不參與類型。
另外一個看函數參數的更改是否會修改值,對于重載函數來說,如果類型變了,那麼這個函數構成重載,如果參數改變導緻值發生改變,那麼函數構成重載。
遇到含有指針和const修飾的變量之間互相指派時,一定要牢記:
1.隻有左右等式的類型相同時,才可以互相指派。
2.左右等式類型不相等,但依然可以指派的隻有一種情況,等式的右邊是普通變量,左邊是const修飾的變量(可以想象成const對資料要求比較高,普通變量對資料要求比較低,高要求可以相容低要求,而反過來不行)。
另外還有以下的小點需要牢記:
1.凡是由寄存器帶出來的值或變量,它們都是立即數,舉例如下:寄存器帶出來以下三類變量:立即數(10)、指針變量(p)、引用變量(a),這三類變量如果其接受者和它們自身的類型相同,那麼完全可以放心大膽的接收,但如果是将這三類變量的位址傳遞出去,那麼必須使用一個安全的變量來接受,以防記憶體洩漏,也就是說要這三類變量自己是不能改變的,如果想要定義一個指針或引用來接受寄存器傳出來的變量,那麼這個指針或引用必須是const修飾的,否則會存在記憶體洩漏問題編譯,導緻無法通過。