C++ const 關鍵字總結

C++ 中關於 const 的知識點不少,在這裏作個總結。express

const 關鍵字修飾的變量在建立後值就不能改變了,所以必須在建立時進行初始化。函數

對象的類型決定了可以在對象上進行哪些操做。對 const 對象來講,只能使用那些不能改變對象狀態的操做。this

若是 const 對象是由一個編譯時常量(compile-time constant)進行初始化的:spa

const int bufSize = 512; // input buffer size 

那麼編譯器通常會在編譯時用這個常量替換該 const 變量。即編譯器把全部用到 bufSize 的地方替換爲512。爲了進行這種替換,顯然編譯器須要知道 const 變量的初值是多少,這就須要檢查 const 變量是如何被定義並初始化的。指針

若是程序分佈在多個文件中,爲了對變量的值進行替換,編譯器在編譯每一個用到該 const 變量的文件時,都須要知道該 const 變量是如何被定義的,這就要求在每一個用到該 const 變量的文件中都對該變量進行定義(define 而不是 declare),然而一個變量是不能被屢次定義的。爲解決這個矛盾,規定 const 變量的做用域是文件自己(local to file)。當咱們在多個文件中定義名字相同的多個 const 變量時,就像在每一個文件中定義了一個不一樣的變量同樣。code

(對於通常變量來講只能在一處進行定義,在其餘文件中使用時須要使用 extern 關鍵字進行聲明。)對象

有時咱們想在多個文件中共享一個 const 變量,可是該 const 變量的初始化器(initializer)並非一個常量表達式(constant expression,常量表達式的值在編譯時就能夠被肯定,如一個數字或算術表達式,一個經過 constant expression 進行初始化的 const 變量也是一個 constant expression)。在這種狀況下,咱們不但願編譯器在每一個用到該 const 變量的文件中都單獨生成一個新的變量。咱們但願在一個文件中進行定義,在其餘文件中進行聲明。要達到這一目標,須要在定義和聲明時同時使用 extern 關鍵字(不然就是 local to file)。ip

// file_1.cc 
extern const int bufSize = fcn(); 
 // file_1.h 
extern const int bufSize; 

下面用代碼具體演示一下。若是是 nonconst 的變量,則只能在一處進行定義。ci

// file_1.cc 
#include <cstdio> 
int bufSize = 512; 
void print(); 
int main() { print(); return 0; } 
// file_2.cc 
#include <cstdio> 
int bufSize = 100; 
int print() { printf("\n%d\n", bufSize); return 0; } 

編譯時報錯:multiple definition of bufSize'。若是將兩個 bufSize 中的一個改成 const,或兩個都改成 const,則編譯經過,輸出 100。作用域

// file_1.cc 
#include <cstdio> 
const int bufSize = 512; 
void print(); 
int main() { print(); return 0; } 
// file_2.cc 
#include <cstdio> 
extern const int bufSize; 
int print() { printf("\n%d\n", bufSize); return 0; } 

若是是這樣,file_1 中進行定義時沒有加 extern 關鍵字,則編譯時報錯:undefined reference to bufSize'

若是將兩個文件中的 const 關鍵字都去掉,或者給 file_1 中的 const 變量也加上 extern 關鍵字,編譯成功,輸出512。

對 const 變量的引用

像普通變量同樣,也能夠將一個引用綁定到一個 const 變量。對 const 變量的引用一樣不能改變該 const 變量的值。

const int ci = 1024; 
const int &r1 = ci; r1 = 42; // 錯誤,不能經過對 const 的引用改變 const 變量的值 
int &r2 = ci; // 錯誤,不能用 nonconst reference 引用 const 變量 

指針,const 和類型別名(type aliases)

考慮下面的代碼:

typedef char *pstring; const pstring cstr = 0; const pstring *ps; 

const 修飾的是 pstring,而 pstring 的類型是指向 char 的指針,因此 const pstring 是一個 constant pointer to char,而非 pointer to const char。

不能經過直接替換來理解類型別名:

const char *cstr = 0; // 這是對 const pstring cstr 的錯誤理解 

const 參數

進行賦值時,top-level const 會被忽略,因此如下兩個函數定義不能同時存在:

void fcn(const int i) {} 
void fcn(int i) {} 

這兩個函數可以接收一樣的參數,因此不算重載。

能夠用 nonconst 對象對 low-level const 對象進行初始化,但不能用 low-level const 對象初始化 nonconst 對象。(low-level const 指針認爲其指向的對象是 const 對象)。

int i = 42; 
const int *cp = &i; // ok: cp 是 low-level const,能夠用 nonconst 進行初始化,但不能經過 cp 改變 i 的值 
const int &r = i; // ok: reference to const,不能經過 r 改變 i 的值 
const int &r2 = 42; // ok 
int *p = cp; // error: 不能用 low-level const 初始化 nonconst,但能夠用 const_cast 強制轉換 
int &r3 = r; // error 
int &r4 = 42; // error: 不能經過 literal 初始化 plain 的 reference 

若是可能就應該使用 reference to const

不用 reference to const,會讓調用者錯誤地認爲函數會改變參數的值。並且不用 reference to const,會限制可以傳遞的參數類型。不能向普通的 reference 傳遞 const 對象,不能傳遞 literal,不能傳遞須要轉換的類型。

const 成員函數

成員函數的參數列表後面能夠加關鍵字 const,做用是修飾 this 指針。

this 指針默認是 const pointer to nonconst object,故不能指向 const object,也就是說 const 對象的方法沒法被調用。將成員函數變爲 const 成員函數,其 this 指針隱含參數變爲 const pointer to const object。const 成員函數不能改變對象狀態。const 對象只能調用 const 成員函數。

注意 const 成員函數若是返回 *this,那麼返回的是一個 const 對象,不能在返回對象基礎上繼續調用 nonconst 的成員函數。爲解決這一點能夠基於成員函數的 constness 對成員函數進行重載。

相關文章
相關標籤/搜索