天天看點

const /*/& 在一起要幹嘛 ?!一、關鍵字Const作用:

一、關鍵字Const作用:

1.可以定義const常量,具有不可變性。 

 例如:const int Max=100; Max++會産生錯誤; 

2.便于進行類型檢查,消除了一些隐患。const常量有資料類型,而宏常量沒有資料類型。編譯器可以對前者進行類型安全檢查,而對後者隻進行字元替換,沒有類型安全檢查,并且在字元替換時可能會産生意料不到的錯誤。

 例如: void f(const int i) { .........}  //編譯器就會知道i是一個常量,不允許修改; 

3.可以避免意義模糊的數字出現,同樣可以很友善地進行參數的調整和修改。 同宏定義一樣,可以做到不變則已,一變都變!如1.中,如果想修改Max的内容,隻需要:const int Max=you want;即可!

4.可以保護被修飾的東西,防止意外的修改,增強程式的健壯性。 還是上面的例子,如果在函數體内修改了i,編譯器就會報錯; 

 例如: void f(const int i)  { i=10; } //error!

5.為函數重載提供了一個參考;

   例如:class A

         {

            ......

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

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

           ......

        };

6. 可以節省空間,避免不必要的記憶體配置設定。const定義常量從彙編的角度來看,隻是給出了對應的記憶體位址,而不是像#define一樣給出的是立即數,是以,const定義的常量在程式運作過程中隻有一份拷貝,而#define定義的常量在記憶體中有若幹份拷貝。 

 例如: 

  #define PI 3.14159 //常量宏 

  const double Pi=3.14159; //此時并未将Pi放入RAM中 ...... 

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

  double I=PI; //編譯期間進行宏替換,配置設定記憶體 

  double j=Pi; //沒有記憶體配置設定 

  double J=PI; //再進行宏替換,又一次配置設定記憶體! 

  

7. 提高了效率。 編譯器通常不為普通const常量配置設定存儲空間,而是将它們儲存在符号表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀記憶體的操作,使得它的效率也很高。

二.Const限定符在C/C++中差別:

1.C語言中的常變量的不可以定義數組。因為C中的常變量和變量唯一的差別是不能作為左值,其他性質都和變量一樣。eg: 在.C中,有三種修改const常變量值的方式:

       int b=20; const int a= 10;

      1) int *p=&a; *p=20;

  1. 2) _asm 

    {mov dword[ebp-8] 14h}

    3) *(&b-1)=20;

C語言中可以引用外部const變量聲明/定義,會生成一個global符号。連結器在連接配接的時候,隻看g符号。而在其前加上static,就會變為local。除了外部常量,外部變量産生的符号也是g。

2 . C++中的常變量可以作為數組的下标,可以定義數組。常變量是常量。但是在某些情況下,會退化為 變量。

     C++中常變量在編譯階段所有出現常量名字的地方會被常量值替換,但不會替換類似&a表達式中的a,當a是const常量時。而C中的常變量在編譯階段并不會被替換。

    C++中不可以引用外部檔案定義的常量,因為産生的是local符号 ;

因為替換的時候隻能在目前檔案中替換。如果要能被外部引用到,在變量定義時加上一個extern,就可将其連結屬性變為global.

     當一個常變量的初始值為外部定義的值時,此時常量就會退換成常變量。因為編譯階段不知道初始值,連結時才知道有這個符号的定義,運作時才會指派。那麼常量的所有彙編也都會變成和變量一樣。

三.Const限定符與&.*的結合:

1.const 和一級指針的結合 :

      當const修飾一個變量名時,并不是意味着這個變量所占的記憶體是const,而是不能通過這個名字對其修改或洩露常量記憶體位址或引用。例如:

const /*/& 在一起要幹嘛 ?!一、關鍵字Const作用:

 常見用法:

      int a = 10;

      const int *p = &a;

      int *q = p;

4.const和二級指針的結合,例如:

1)常見錯誤:

int a = 10;

int *p = &a;

const int **q = &p;

int** -> const int **: const修飾的哪個變量就先改變哪一邊 *q<->p這裡的*p會洩露常量位址,是以出錯!如果,**q<->*p,将一個常量的值放入const修飾的變量中,則不會出錯。

2)經過修改之後:

    int a = 10;

    int *p = &a;

    const int * const *q  = p;//這裡組織*q被非法修改;

3)又如:

int a = 10;

int *p = &a;

    int  * const *q  = &p;//**q<->*p也沒有問題;

 4)當const和指針結合時,若const右邊無指針時,有沒有const無差別。是以不能構成重載。 

void func(const int a)

{

}

void func(int b)

{

}

  5)當對實參的值有影響時,才會構成重載。下面這個就可以構成重載。 

void func(const int* a)

{

}

void func(int* b)

{

}

6)類型轉換總結: 

錯誤的類型轉換:會把常量的位址放在一個普通的指針裡面!!

    int * - > const int *       --> right

    const int * -> int *       --> error!

int **- > const int **  <相當于>  int *& -> const int *  --> error! 

const int ** -> int **   <相當于> const int *& -> int *  --> error!

int* const * -> int **    -->error!

//const跟多級指針結合,必須兩邊都給修飾!!

5.引用:

     引用就是一個指針,無論是什麼時候占四個位元組。 

     C++中一個空類占一個位元組(不同編譯器不一樣,有的不可以定義) 

    struct 

   { 

      char a; 

      char b; 

      char c; 

   }data; 

   //sizeof(data)=3

6.const 跟 */&的結合:

     引用在使用時自動解引用 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

    sizeof(p)=16 (引用了一個數組) 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

//sizeof(p)=16

如果不好直接寫引用,可以在寫的時候可以先寫成一個函數指針(引用數組名),然後改為引用。

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

在這個記憶體位址上寫一個四位元組的整數10 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

     int p=(int )0x0018ff44 

     *p=10;

//要想定義一個引用變量,如果右邊位址不可取,就弄一個常引用

int const &p=(int )0x0018ff44 

     *p=10; 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

下面的錯誤,是vc的一個bug,編譯器檢測不出淚,vs可以檢測出來

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

相當于将int**轉化為一個const int *,從引用角度來看,p和q是同一塊記憶體,int 和const int *不能是同一塊記憶體。是以錯誤 !

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

錯誤, p是一個const常量,由于*q=p,是以最後一句應改為 

      int *const*q=&p; 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

    //由于*q<->p,是以給*q賦一個整型常量的位址也就是相當于給p附一個整型常量位址,但是這樣會使得整型常量位址洩露,是以修改的辦法有兩種防止位址洩露被修改: 

1) 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

//讓*p為常量,防止它被指派。 

2) 

const /*/&amp; 在一起要幹嘛 ?!一、關鍵字Const作用:

//禁止*q的改變,達到給p指派的目的

7.C++11中出現了左引用和右引用。 

     引用占記憶體,四個位元組,&b列印出來就是a的位址,引用位址就是所引用變量的位址,使用引用時,自動解引用。

1)左值引用

   左值引用隻能綁定左值,不能綁定右值.

如下:

[cpp] view plain copy

  1. int x = 1;  
  2. int &y = x;                //綁定左值,正确  
  3. int &z = 2;                //綁定右值2,編譯錯誤  

但是可以将右值綁定到一個const左值引用(這是一個例外)

如:

[cpp] view plain copy

  1. //右值綁定到const左值引用  
  2. nt const &i = 28;                 //正确  

在右值引用誕生之前,為了傳遞臨時對象到函數中以引用,這将允許實參隐式轉換到形參類型,如下:

[cpp] view plain copy

  1. void print(std::string cosnt& s) {}  
  2. print("hello");        //“hello”字元串是臨時字元串對象,也是右值  

2)右值引用

   右值引用隻能綁定右值,不能綁定左值.使用兩個&&表示右值引用.

如:

[cpp] view plain copy

  1. int&& i = 8;              
  2. int j = 18;         
  3. int&& k = j;               //編譯錯誤  

通過使用函數重載來決定函數參數是左值/右值,重載函數參數設定為左值引用和右值引用.

[cpp] view plain copy

  1. void fun_reference(int& a)  
  2. {  
  3.      std::cout << "左值引用:" << a << std::endl;  
  4. }  
  5. void fun_reference(int&& a)  
  6. {  
  7.      std::cout << "右值引用:" << a << std::endl;  
  8. }  
  9. int main()  
  10. {  
  11.     int x = 8;  
  12.     fun_reference(x);     //輸出左值引用:8  
  13.     fun_reference(18);  //輸出右值引用:18  
  14.     return 0;  
  15. }  

[就暫且先總結這麼多吧,水準跟見識也有限,還望大家多多批評指正!!]