const 這個關鍵字會將所修飾的表達式置爲常量,編譯器會盡全力保證該表達式不可被修改,在const不和指針或者引用結合是,數據的類型是無關const的,可是若是一但和指針和引用相結合,那麼考慮數據類型時候必需要考慮const了指針
class Test { public: Test(int data = 10):_ptr(new int(data)){} ~Test(){ delete _ptr; } int GetInt(){ return *_ptr; } int GetInt()const{ return *_ptr; } int& GetIntRef(){ return *_ptr; } int& GetIntRef()const{ return *_ptr; } int* GetIntPtr(){ return _ptr; } int* GetIntPtr()const{ return _ptr; } // int *const _ptr int*& GetIntPtrRef(){ return _ptr; } int*const& GetIntPtrRef()const{ return _ptr; } private: int *_ptr; }; int main() { Test t1; const Test t2; int a1 = t1.GetInt(); int &b1 = t1.GetInt(); const int &c1 = t1.GetInt(); int a2 = t2.GetInt(); int &b2 = t2.GetInt(); const int &c2 = t2.GetInt(); return 0; }
上面代碼種b1是錯誤的,b2也是
先來看看b1,getInt返回的是一個整形值,它所返回的是一個當即數,那麼用引用接收的時候就會出現沒法給當即數取址的問題,此時寄存器帶出的是一個當即數,而當即數不會有地址的,因此若是要引用,必須是一個常引用,不然編譯不經過。
b2也是一樣的,當即數不能取址code
int main() { Test t1; const Test t2; int a1 = t1.GetIntRef(); int &b1 = t1.GetIntRef(); const int &c1 = t1.GetIntRef(); int a2 = t2.GetIntRef(); int &b2 = t2.GetIntRef(); const int &c2 = t2.GetIntRef(); return 0; }
這樣編譯下來,並無什麼問題,緣由是返回一個引用,此時會生成一個臨時量,不存在當即數的問題了對象
int main() { Test t1; const Test t2; int *a1 = t1.GetIntPtr(); int *&b1 = t1.GetIntPtr(); const int *&c1 = t1.GetIntPtr(); int *a2 = t2.GetIntPtr(); int *&b2 = t2.GetIntPtr(); const int *&c2 = t2.GetIntPtr(); return 0; }
此時又出現了剛纔的問題,指針自己也是一個在32位系統下4字節的基礎類型,因此返回值也會是一個當即數,不能取址,必須用常引用內存
簡單總結一下:
對於賦值表達式的兩邊get
再補充3個例子編譯器
int*& GetIntPtrRef(){ return _ptr; } int*const& GetIntPtrRef()const{ return _ptr; } int main() { Test t1; const Test t2; int *a1 = t1.GetIntPtrRef(); int *&b1 = t1.GetIntPtrRef(); const int *&c1 = t1.GetIntPtrRef(); int *a2 = t2.GetIntPtrRef(); int * &b2 = t2.GetIntPtrRef(); const int *&c2 = t2.GetIntPtrRef(); return 0; }
此時編譯下來有3個錯誤,本質上仍是類型不相同致使的,GetIntPtrRef()const的返回值是int const,可是b2是一個int *&,因此須要再&前面加上const保持類型相同
c2也是同樣的道理,須要再引用前面加const編譯
這裏還有一個c1的錯誤,這個錯誤有些特殊,前面說過,const修飾的變量,編譯器會盡力保證這個值不可被修改,此時const修飾的是&c1這個表達式,因此經過c1是不能修改的,可是此時卻能夠經過c1這個引用變量修改c1的內存,將引用換個指針就更加明顯了,q,p這兩個變量均可以修改同一片內存,此時咱們告訴編譯器,q這是個常量,不許修改了,可是編譯器發現經過*p竟然也能夠修改這裏的內存,必然是經過不了的。修改的話能夠限定常引用,防止修改同一片內存class
const int *const &c1 = t1.GetIntPtrRef();
int ** GetIntPtrPtr() { return &_ptr; } int *const* GetIntPtrPtr()const{ return &_ptr; } int main() { Test t1; const Test t2; int **a1 = t1.GetIntPtrPtr(); int **b1 = t1.GetIntPtrPtr(); const int **c1 = t1.GetIntPtrPtr(); int **a2 = t2.GetIntPtrPtr(); int **b2 = t2.GetIntPtrPtr(); const int **c2 = t2.GetIntPtrPtr(); return 0; }
此時有4個錯誤,再常對象t2中_ptr是一個常量不可被修改的,因此 t2全部接收的類型都是int const ,故而a2,b2,c2都有錯誤
而c1中也就是那個特殊的錯誤,const修飾的變量編譯器會盡力防止內存修改,因此應該是const int const 類型,故而c1也有錯誤基礎
int ** const& GetIntPtrPtrRef(){ return &_ptr; } int *const * const& GetIntPtrPtrRef()const{ return &_ptr; } int main() { Test t1; const Test t2; int **a1 = t1.GetIntPtrPtrRef(); int **b1 = t1.GetIntPtrPtrRef(); const int **c1 = t1.GetIntPtrPtrRef(); int **a2 = t2.GetIntPtrPtrRef(); int **b2 = t2.GetIntPtrPtrRef(); const int **c2 = t2.GetIntPtrPtrRef(); return 0; }
這個的錯誤和上個例子十分類似,在此很少贅述了。變量