標籤:資料 整數 常指標 保留 特性 post 解構函式 指標 center
1、C語言中const與 C++中的const
void main(){ const int a = 10; int *p = (int*)&a; *p = 20; printf("%d", a);}
比較上述代碼在C中和C++中執行結果:C:列印20;C++:列印0。
由此可見,C語言中的const是個“冒牌貨”,C++中 的const是一個真正的常量。
原因:C語言直接為a分配了記憶體。
C語言中的const變數是僅僅讀變數,有自己的儲存空間。而C++編譯器對const的處理是:當碰見常量聲明時,在“符號表”(C++編譯器專門設定的)中放入常量,在使用a的時候直接在符號表中取值。 那麼問題是那又怎樣解釋取地址呢?
A.編譯過程中若發現使用常量則直接以符號表中的值替換;
B.編譯過程中若發現對const使用了extern(須要在其它檔案裡使用) 或者 &操作符,則給const常量另外再專門分配儲存空間。
如所看到的,對const變數取地址後,為“20”單獨專門分配了空間。而與符號表中的a沒有關係。
2、const與基礎資料類型:
const int bufsize = 512。bufsize的值不能再被改動。不論什麼試圖為bufsize賦值的行為都將引發錯誤。由於const的對象一旦建立後其值不能再改變,所以const對象必須初始化。 int i=12;const int ci=i;還能夠利用另外一個對象(是不是const無關緊要)去初始化const對象。。
。int j = ci。一旦拷貝完畢,新的對象和原來的對象就沒有什麼關係了。{ int i = 50; const int j = i; //初始化 int k = j; int m = 100; //j = m; //賦值,編譯錯誤}
預設狀態下,const對象僅在檔案內有效。當多個檔案裡出現了同名的const對象,事實上等同於在不同檔案定義了獨立的變數。
假設const對象須要在不同檔案分享權限設定,那就須要對const對象無論是聲明還是定義都加入externkeyword。
注意僅僅能定義一次:extern const int bufsize = 512。一般被包括在標頭檔。
在使用時直接聲明:extern const int bufsize;不能再定義,否則出錯。
extern就說明了bufsize並非本檔案專屬,它的定義在別處。
3、const與引用
void main(){ //對常量對象 只能 用 常量引用 const int ci = 100; //常量對象 const int &ri = ci; //正確:引用及其相應的對象都是常量 //ri = 100; //error:ri是對常量的引用 //int &r2 = ci; //error:將一個很量引用指向一個常量對象,假設正確,那麼將能夠通過改動r2來改變ci的值,ci顯然不能改變。 //常量引用 同意被 綁定到 很量的對象、 字面值、 一般運算式 ————例外1 int i = 50; const int &CRi1 = i; //很量的對象 const int &CRi2 = 500; //字面值 const int &CRi3 = i * 2; //一般運算式 int r4 = CRi1 * 2; //正確:CRi1的常量特徵只在運行改變的時候才會發生作用,拷貝賦值並不會改變。一旦拷貝完畢,新的對象和原來的對象就沒有什麼關係了。 //int &r5 = CRi1 * 2; //error:將一個很量引用指向一個常量對象。假設正確。那麼將能夠通過改動r5來改變CRi1的值,CRi1顯然不能改變。 /* * * * * * * * * *一般來說。引用的類型必須與其所引用對象的類型一致。 *當一個常量引用被綁定到第二種類型上究竟發生了什嗎? * double d = 3.14; const int &ri = d; * const int tmp = d; // 由雙精確度浮點數產生一個暫時的整型常量 const int &ri = d; // 讓ri綁定這個暫時的常量 * * * * * * * * */ //常量引用只對自己可參與的操作做了限定,假設引用的對象是個很量,那麼同意通過其它途徑改變它的值 int j = 10; int &rj = j; //引用rj 綁定 對象j const int &cj = j; //常量引用cj 也綁定 對象j。可是不同意通過cj 去改動j的值 rj = 1000; //通過rj 改動j,j被改動為1000 //cj = 1000; cout << "j: " << j << " ,cj: " << cj << endl; //j: 1000 ,cj: 1000}
const引用傳遞對象(非內建類型):
(1)效率高:沒有不論什麼新的對象被建立,所以也就不會調用不論什麼的建構函式和解構函式。(內建類型值傳遞方式效率高)
(2)能夠避免對象被分割:假設衍生類別對象以值傳遞方式賦值給基類。衍生類別的特化性質會被所有分割,只留下一個base類對象。
4、const與指標
所謂指向常量 的指標或者引用。只是是指標或引用“自以為是”罷了,它們自己認為自己指向了常量,所以自覺地不去改變它所指向的對象的值。(可是常量 的指標或者引用 是能夠 指向很量的,而很量是能夠通過其它途徑改變的)。
指標是對象,而引用不是!因此。指標本身是不是常量 和 指標所指的是不是一個常量 是兩個相互獨立的問題!
頂層const——指標本身是個常量!
底層const——指標所指的對象是個常量。
void main(){ int i = 10, m = 20; const int ci = 100, cm = 200; //第一、二個意思一樣,代表一個 常整形數,不論什麼試圖為a、b賦值的行為都將引發錯誤 const int a = 0; //必須初始化 int const b = 1; //第三個 c是一個指向常整形數的指標(所指向的記憶體資料不能被改動,可是本身能夠改動) const int *c1 = &ci; //int *c2 = &ci; //存放常量的地址,僅僅能使用指向常量的指標 const int *c = &i; //*c = m; //c指向的記憶體資料是const的(c的自我感覺),也就是不能通過 *c “直接改動”的 c = &m; //c的值是同意改動的(底層const)。改動c的指向。讓c指向另外一個記憶體空間 cout << *c << endl; //20 //第四個 d 常指標————指標本身是個常量(指標變數(指向)不能被改動,可是它所指向記憶體空間能夠被改動) int ii = 0; int * const d = ? //d 將一直指向 ii (頂層const),不同意改動 d 的值 *d = 250; //指標本身是個常量,並不意味著不能通過改動指標所指向的值。(依賴於所指向的對象) cout << ii << endl; // ii 被改動成250。(d指向的是一個很量) //第五個 e 一個指向常整形的常指標(指標和它所指向的記憶體空間,均不能被改動) const int pi = 123; const int * const e = π //e所指的對象值 和 e自己儲存的那個地址 都不能改變}
5、const與成員函數
將const實施與成員函數的目的,是為了確認該成員函數可作用於const對象身上(非const成員函數本來就能夠對其對象做不論什麼操作,所以在當中調用一個const成員函數也正確)。
兩個函數假設僅僅是常量性(一個是const成員函數,一個是非const成員函數)不同。也能夠被重載。作為一種良好的編程風格,在聲明一個成員函數時,若該成員函數並不正確資料成員進行改動操作,應儘可能將該成員函式宣告為const 成員函數。在C++中。僅僅有被聲明為const的成員函數才幹被一個const類對象調用。把一個成員函式宣告為const能夠保證這個成員函數不改動資料成員。可是,假設據成員是指標,則const成員函數並不能保證不改動指標指向的對象,編譯器不會把這樣的改動檢測為錯誤。
int foo(int *test) const;//可看做:int foo(const A *this,int *test);
6、const與define
const修飾的常量編譯期間,就確定下來。const常量是由編譯器處理的,提供類型檢查和範圍檢查;宏定義由前置處理器處理。單純的文本替換。
void fun1(){ #define a 10 const int b = 20; //#undef a //將宏定義a卸載,限制範圍} void fun2(){ printf("a = %d\n", a); //printf("b = %d\n", b); //const定義的b是有範圍的}
7、const與constexpr
constexpr:常量運算式,指的是值不會改變而且在編譯過程中就能得到計算結果的運算式。
由資料類型和初始值共同決定。
const int max = 100; //max是常量運算式 const int limit = max + 1; //limit是常量運算式 int size = 50; //size不是常量運算式,僅僅一個普通的int類型 const int sz = get_size(); //sz本身是個常量,但它的值直到執行時才幹確定,所以不是常量運算式 一般說來,假設你認定變數是一個常量運算式。那就把它聲明成constexpr類型。 const int sz = get_size(); //僅僅有get_size()是一個constexptr函數時。才是一條正確的聲明語句。
8、const與auto
auto通常會忽略掉頂層const。同一時候底層const則會保留。
void main(){ //auto通常會忽略掉頂層const,同一時候底層const則會保留。 int i = 10; const int ci = i; const int &cr = ci; auto b = ci; //b是一個int(ci的頂層const特性被忽略) auto c = cr; //c是一個int(cr是ci的別名,ci的頂層const特性被忽略) auto d = &i; //d是一個整型指標(整數的地址就是指向整數的指標) auto e = &ci; //e是一個指向整型常量的指標(對常量對象 取地址 是一種底層const) //假設希望判斷出的auto類型是一個頂層const。則需明白指出 const auto f = ci; //ci的推演類型是int,f是const //還能夠將引用設為auto,原來的初始化規則仍然適用 auto &g = ci; //g是一個常量引用。綁定到ci //auto &h = 42; //error:顯然不能為一個字面值綁定很量引用。
(怎麼說?h是42的引用?字面量42沒有記憶體空間 沒有辦法做引用) const auto &j = 42; //正確:能夠為常量引用綁定字面值}
9、const與decltype
decltype處理頂層const和引用的方式與auto不同。假設decltype使用的運算式是一個變數,則decltype返回該變數的類型。
int i = 10;const int ci = i;const int &cr = ci;decltype(ci) x = 0; //x的類型是const intdecltype(cr) y = x; //y的類型是const int&。y綁定到x//decltype(cr) z; //error:z是一個引用,必須初始化
10、const與迭代器
vector<int> vec;const vector<int>::iterator ite = vec.begin(); //ite 相當於T× const*ite = 10; //正確,改變ite所指之物++ite; //錯誤,ite是const的vector<int>::const_iterator conIte = vec.begin(); //conIte相當於 const T×*conIte = 10; //錯誤,×conIte是const的++conIte; //正確,改變conIte
概覽C++之const