1. 程式人生 > >C++精進篇(三)之―常量變數等修飾符

C++精進篇(三)之―常量變數等修飾符

一、Const常量

1、Const定義:

常型別是指使用型別修飾符const修飾的型別,常型別的變數或物件的值是不能被更新的。const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點。

2、Const作用:

1)可以定義const常量,具有不可變性。例如:
               const int Max=100; int Array[Max]; 
<span style="color:#333333;">(</span><span style="color:#333333;">2</span><span style="color:#333333;">)便於進行型別檢查,使編譯器對處理內容有更多瞭解,消除了一些隱患。</span>
<span style="color:#333333;">例如:</span><span style="color:#333333;"> void f(const int i) { .........} </span><span style="color:#333333;">編譯器就會知道</span><span style="color:#333333;">i</span><span style="color:#333333;">是一個常量,不允許修改。</span>
<span style="color:#333333;">(</span><span style="color:#333333;">3</span><span style="color:#333333;">)可以避免意義模糊的數字出現,同樣可以很方便地進行引數的調整和修改。</span><span style="color:#333333;">同巨集定義一樣,可以做到不變則已,一變都變!如(</span><span style="color:#333333;">1</span><span style="color:#333333;">)中,如果想修改</span><span style="color:#333333;">Max</span><span style="color:#333333;">的內容,只需要:</span><span style="color:#333333;">const int Max=you want;</span><span style="color:#333333;">即可!</span>
<span style="color:#333333;"> </span><span style="color:#333333;">(</span><span style="color:#333333;">4</span><span style="color:#333333;">)可以保護被修飾的東西,防止意外的修改,增強程式的健壯性。</span><span style="color:#333333;">還是上面的例子,如果在函式體內修改了</span><span style="color:#333333;">i</span><span style="color:#333333;">,編譯器就會報錯;</span><span style="color:#333333;">例如:</span>
void f(const int i) { i=10;//error! } 
<span style="color:#333333;">(</span><span style="color:#333333;">5</span><span style="color:#333333;">)</span><span style="color:#333333;">為函式過載提供了一個參考。例如如下程式碼:</span>

class A { ......

void f(int i) {......} //一個函式

void f(int i) const {......} //上一個函式的過載 ......

};

6可以節省空間,避免不必要的記憶體分配。例如如下程式碼:

#define PI 3.14159 //常量巨集   

const doulbe Pi=3.14159; //此時並未將Pi放入ROM中 ......   

double i=Pi; //此時為Pi分配記憶體,以後不再分配!   

double I=PI; //編譯期間進行巨集替換,分配記憶體   

double j=Pi; //沒有記憶體分配   

double J=PI; //再進行巨集替換,又一次分配記憶體!   

const定義常量從彙編的角度來看,只是給出了對應的記憶體地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程式執行過程中只有一份拷貝,而#define定義的常量在記憶體中有若干個拷貝。
<span style="color:#333333;">(</span><span style="color:#333333;">7</span><span style="color:#333333;">)</span><span style="color:#333333;">提高了效率。</span><span style="color:#333333;">編譯器通常不為普通</span><span style="color:#333333;">const</span><span style="color:#333333;">常量分配儲存空間,而是將它們儲存在符號表中,這使得它成為一個編譯期間的常量,沒有了儲存與讀記憶體的操作,使得它的效率也很高。</span>

3、Const常用的幾種情形:

1)修飾一般常量一般常量是指簡單型別的常量。這種常量在定義時,修飾符const可以用在型別說明符前,也可以用在型別說明符後。
<span style="color:#333333;">               </span><span style="color:#333333;">例如:</span><span style="color:#333333;"> int const x=2; </span><span style="color:#333333;">或</span><span style="color:#333333;"> const int x=2; </span>
<span style="color:#333333;">(</span><span style="color:#333333;">2</span><span style="color:#333333;">)修飾常陣列</span><span style="color:#333333;">定義或說明一個常陣列可採用如下格式:</span>
<span style="color:#333333;">               int const a[5]={1, 2, 3, 4, 5}; </span>
<span style="color:#333333;">               const int a[5]={1, 2, 3, 4, 5}; </span>
<span style="color:#333333;">(</span><span style="color:#333333;">3</span><span style="color:#333333;">)修飾常物件</span><span style="color:#333333;">常物件是指物件常量,定義格式如下:</span><span style="color:#333333;">   </span>
<span style="color:#333333;">               class A; </span>
<span style="color:#333333;">               const A a; </span>
               A const a; 
<span style="color:#333333;">定義常物件時,同樣要進行初始化,並且該物件不能再被更新,修飾符</span><span style="color:#333333;">const</span><span style="color:#333333;">可以放在類名後面,也可以放在類名前面。</span><span style="color:#333333;"> </span>
<span style="color:#333333;">(</span><span style="color:#333333;">4</span><span style="color:#333333;">)修飾常指標</span>
               const int *A; //const修飾指向的物件,A可變,A指向的物件不可變
               int const *A; //const修飾指向的物件,A可變,A指向的物件不可變
               int *const A; //const修飾指標A A不可變,A指向的物件可變
               const int *const A;//指標AA指向的物件都不可變
<span style="color:#333333;">(</span><span style="color:#333333;">5</span><span style="color:#333333;">)修飾常引用</span><span style="color:#333333;">使用</span><span style="color:#333333;">const</span><span style="color:#333333;">修飾符也可以說明引用,被說明的引用為常引用,該引用所引用的物件不能被更新。</span>
<span style="color:#333333;">               </span><span style="color:#333333;">其定義格式如下:</span>
               const double & v; 
<span style="color:#333333;">(</span><span style="color:#333333;">6</span><span style="color:#333333;">)修飾函式的常引數</span><span style="color:#333333;"> const</span><span style="color:#333333;">修飾符也可以修飾函式的傳遞引數,格式如下:</span>
               void Fun(const int Var); 告訴編譯器Var在函式體中的無法改變,從而防止了使用者的一些無意的或錯誤的修改。
<span style="color:#333333;">(</span><span style="color:#333333;">7</span><span style="color:#333333;">)修飾函式的返回值:</span><span style="color:#333333;"> const</span><span style="color:#333333;">修飾符也可以修飾函式的返回值,是返回值不可被改變,格式如下:</span>
               const int Fun1(); const MyClass Fun2(); 
<span style="color:#333333;">(</span><span style="color:#333333;">8</span><span style="color:#333333;">)修飾類的成員函式:</span><span style="color:#333333;"> const</span><span style="color:#333333;">修飾符也可以修飾類的成員函式,格式如下:</span>

class ClassName {   

public:   

int Fun() const; .....   

};   

這樣,在呼叫函式Fun時就不能修改類裡面的資料
<span style="color:#333333;">(</span><span style="color:#333333;">9</span><span style="color:#333333;">)在另一連線檔案中引用</span><span style="color:#333333;">const</span><span style="color:#333333;">常量</span>
               extern const int i;//正確的引用
               extern const int j=10;//錯誤!常量不可以被再次賦值,另外,還要注意,常量必須初始化!例如: const int i=5; 
10const修飾this指標
this指標是個什麼型別的?這要看具體情況:如果在非const成員函式中,this指標只是一個類型別的;如果在const成員函式中,this指標是一個const類型別的;如果在volatile成員函式中,this指標就是一個volatile類型別的。

二、auto

1、使用迭代器:

vector<vector<int> > v;

vector<vector<int> >::iterator it = v.begin();

2、函式指標也同樣, 型別宣告很特別:

int add(int x,int y){

    return x+y;

}

int main(){

    int (*func)(int,int) =add;

    cout<<func(1,2)<<endl;

}

3、既然把v.begin()賦給it, 型別已經在編譯期確定了,編譯器知道正確的型別是什麼,再加一個型別宣告實在很繁瑣。C++11有了auto。我們可以這樣寫:

vector<vector<int>> v; // C++11 可以不用在'>>'之間加空格了! auto it = v.begin();

auto func = add;

編譯器會根據值的型別,推匯出autob變數。型別的推導是在編譯期就完成的,仍是靜態型別,和指令碼語言不同。實際上是一個語法糖。但由於C++對模板的大量使用,一個變數的型別有時過於複雜難以寫出,這樣的語法糖是必要的。

三、decltype

1、有時候,我們需要讓編譯器根據表示式來確定資料型別,但又不初始化這個變數。這個時候就可以使用decltype關鍵字: decltype(f())sum = x; 2、函式f()並不會被呼叫,但是它的返回值型別會在這裡被使用。 decltype不同於auto,它會完整的保留const int i = 42, *p = &i, &r = i; decltype(r+ 0) b; decltype(*p)c; decltype(r)是一個引用型別,而decltype(r + 0)是一個int型別。 decltype(*p)表示返回的將是一個引用,即int&。 3、還需要注意括號的使用: decltype((i))d; // 錯誤的表達,d是int&,必須被初始化。 decltype(i)e;   // 正確的表達,e是int。注意:不加括號,返回的是變數型別;加了括號,返回的是表示式,賦值表示式會產生一個“=”左邊的型別的引用。

四、變數別名 1、變數別名可以使用typedef: typedefdouble wages;也可以使用using: using SI= Sales_item; 2、變數別名和const結合,會產生有趣的結果: typedefchar *pstring; constpstring cstr = 0; cstr是指向char型別的常量指標,因為const要和base type結合。 3、這裡,物件可以被更改,但cstr不可被更改。 typedef不是define,不能直接替代變數的內容。