cpp知識彙總(1) 指針vs引用、static、const

引用和指針的區別?

  1. 指針是一個實體,需要分配內存空間。引用只是變量的別名,不需要分配內存空間。
  2. 引用在定義的時候必須進行初始化,並且不能夠改變。指針在定義的時候不一定要初始化,並且指向的空間可變。(注:不能有引用的值不能爲NULL)
  3. 有多級指針,但是沒有多級引用,只能有一級引用。
  4. 指針和引用的自增運算結果不一樣。(指針是指向下一個空間,引用時引用的變量值加1)
  5. sizeof 引用得到的是所指向的變量(對象)的大小,而sizeof 指針得到的是指針本身的大小。
  6. 引用訪問一個變量是直接訪問,而指針訪問一個變量是間接訪問。
  7. 使用指針前最好做類型檢查,防止野指針的出現;
  8. 引用底層是通過指針實現的;
  9. 作爲參數時也不同,傳指針的實質是傳值,傳遞的值是指針的地址;傳引用的實質是傳地址,傳遞的是變量的地址。

從彙編層去解釋一下引用

  1. 9:          int x = 1;
  2. 00401048    mov         dword ptr [ebp-4],1
  3. 10:         int &b = x;
  4. 0040104F    lea         eax,[ebp-4]
  5. 00401052    mov         dword ptr [ebp-8],eax

x的地址爲ebp-4,b的地址爲ebp-8,因爲棧內的變量內存是從高往低進行分配的。所以b的地址比x的低。lea eax,[ebp-4]  這條語句將x的地址ebp-4放入eax寄存器mov dword ptr [ebp-8],eax 這條語句將eax的值放入b的地址ebp-8中上面兩條彙編的作用即:將x的地址存入變量b中,這不和將某個變量的地址存入指針變量是一樣的嗎?所以從彙編層次來看,的確引用是通過指針來實現的。

C++中的指針參數傳遞和引用參數傳遞

  1. 指針參數傳遞本質上是值傳遞,它所傳遞的是一個地址值。值傳遞過程中,被調函數的形式參數作爲被調函數的局部變量處理,會在棧中開闢內存空間以存放由主調函數傳遞進來的實參值,從而形成了實參的一個副本(替身)。值傳遞的特點是,被調函數對形式參數的任何操作都是作爲局部變量進行的,不會影響主調函數的實參變量的值(形參指針變了,實參指針不會變)。
  2. 引用參數傳遞過程中,被調函數的形式參數也作爲局部變量在棧中開闢了內存空間,但是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參(本體)的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調函數中的實參變量(根據別名找到主調函數中的本體)。因此,被調函數對形參的任何操作都會影響主調函數中的實參變量。
  3. 引用傳遞和指針傳遞是不同的,雖然他們都是在被調函數棧空間上的一個局部變量,但是任何對於引用參數的處理都會通過一個間接尋址的方式操作到主調函數中的相關變量。而對於指針傳遞的參數,如果改變被調函數中的指針地址,它將應用不到主調函數的相關變量。如果想通過指針參數傳遞來改變主調函數中的相關變量(地址),那就得使用指向指針的指針或者指針引用。
  4. 從編譯的角度來講,程序在編譯時分別將指針和引用添加到符號表上,符號表中記錄的是變量名及變量所對應地址。指針變量在符號表上對應的地址值爲指針變量的地址值,而引用在符號表上對應的地址值爲引用對象的地址值(與實參名字不同,地址相同)。符號表生成之後就不會再改,因此指針可以改變其指向的對象(指針變量中的值可以改),而引用對象則不能修改。
  1. 值傳遞:有一個形參向函數所屬的棧拷貝數據的過程,如果值傳遞的對象是類對象    或是大的結構體對象,將耗費一定的時間和空間。(傳值)
  2. 指針傳遞:同樣有一個形參向函數所屬的棧拷貝數據的過程,但拷貝的數據是一個固定爲4字節的地址。(傳值,傳遞的是地址值)
  3. 引用傳遞:同樣有上述的數據拷貝過程,但其是針對地址的,相當於爲該數據所在的地址起了一個別名。(傳地址)
  4. 效率上講,指針傳遞和引用傳遞比值傳遞效率高。一般主張使用引用傳遞,代碼邏輯上更加緊湊、清晰。

 

static的用法和作用?

1.先來介紹它的第一條也是最重要的一條:隱藏。(static函數,static變量均可)

當同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。

2.static的第二個作用是保持變量內容的持久。(static變量中的記憶功能和全局生存期)存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化,也是唯一的一次初始化。共有兩種變量存儲在靜態存儲區:全局變量和static變量,只不過和全局變量比起來,static可以控制變量的可見範圍,說到底static還是用來隱藏的。

3.static的第三個作用是默認初始化爲0(static變量)

其實全局變量也具備這一屬性,因爲全局變量也存儲在靜態數據區。在靜態數據區,內存中所有的字節默認值都是0x00,某些時候這一特點可以減少程序員的工作量。

4.static的第四個作用:C++中的類成員聲明static

  1. 函數體內static變量的作用範圍爲該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;  
  2. 在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;   
  3. 在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內;   
  4. 在類中的static成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝;   
  5. 在類中的static成員函數屬於整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。

類內:

  1. static類對象必須要在類外進行初始化,static修飾的變量先於對象存在,所以static修飾的變量要在類外初始化;
  2. 由於static修飾的類成員屬於類,不屬於對象,因此static類成員函數是沒有this指針的,this指針是指向本對象的指針。正因爲沒有this指針,所以static類成員函數不能訪問非static的類成員,只能訪問 static修飾的類成員;
  3. static成員函數不能被virtual修飾,static成員不屬於任何對象或實例,所以加上virtual沒有任何實際意義;靜態成員函數沒有this指針,虛函數的實現是爲每一個對象分配一個vptr指針,而vptr是通過this指針調用的,所以不能爲virtual;虛函數的調用關係,this->vptr->ctable->virtual function

 

 

靜態變量什麼時候初始化

 

  1. 初始化只有一次,但是可以多次賦值,在主程序之前,編譯器已經爲其分配好了內存。
  2. 靜態局部變量和全局變量一樣,數據都存放在全局區域,所以在主程序之前,編譯器已經爲其分配好了內存,但在C和C++中靜態局部變量的初始化節點又有點不太一樣。在C中,初始化發生在代碼執行之前,編譯階段分配好內存之後,就會進行初始化,所以我們看到在C語言中無法使用變量對靜態局部變量進行初始化,在程序運行結束,變量所處的全局內存會被全部回收。
  3. 而在C++中,初始化時在執行相關代碼時纔會進行初始化,主要是由於C++引入對象後,要進行初始化必須執行相應構造函數和析構函數,在構造函數或析構函數中經常會需要進行某些程序中需要進行的特定操作,並非簡單地分配內存。所以C++標準定爲全局或靜態對象是有首次用到時纔會進行構造,並通過atexit()來管理。在程序結束,按照構造順序反方向進行逐個析構。所以在C++中是可以使用變量對靜態局部變量進行初始化的。

const?

  1. 阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因爲以後就沒有機會再去改變它了;   
  2. 對指針來說,可以指定指針本身爲const,也可以指定指針所指的數據爲const,或二者同時指定爲const;   
  3. 在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;   
  4. 對於類的成員函數,若指定其爲const類型,則表明其是一個常函數,不能修改類的成員變量,類的常對象只能訪問類的常成員函數;   
  5. 對於類的成員函數,有時候必須指定其返回值爲const類型,以使得其返回值不爲“左值”。
  6. const成員函數可以訪問非const對象的非const數據成員、const數據成員,也可以訪問const對象內的所有數據成員;
  7. 非const成員函數可以訪問非const對象的非const數據成員、const數據成員,但不可以訪問const對象的任意數據成員;
  8. 一個沒有明確聲明爲const的成員函數被看作是將要修改對象中數據成員的函數,而且編譯器不允許它爲一個const對象所調用。因此const對象只能調用const成員函數。
  9. const類型變量可以通過類型轉換符const_cast將const類型轉換爲非const類型;
  10. const類型變量必須定義的時候進行初始化,因此也導致如果類的成員變量有const類型的變量,那麼該變量必須在類的初始化列表中進行初始化;
  11. 對於函數值傳遞的情況,因爲參數傳遞是通過複製實參創建一個臨時變量傳遞進函數的,函數內只能改變臨時變量,但無法改變實參。則這個時候無論加不加const對實參不會產生任何影響。但是在引用或指針傳遞函數調用中,因爲傳進去的是一個引用或指針,這樣函數內部可以改變引用或指針所指向的變量,這時const 纔是實實在在地保護了實參所指向的變量。因爲在編譯階段編譯器對調用函數的選擇是根據實參進行的,所以,只有引用傳遞和指針傳遞可以用是否加const來重載。一個擁有頂層const的形參無法和另一個沒有頂層const的形參區分開來。

const成員函數的理解和應用?

const Stock & Stock::topval (②const Stock & s) ③const

處const:確保返回的Stock對象在以後的使用中不能被修改

處const:確保此方法不修改傳遞的參數 S

處const:保證此方法不修改調用它的對象,const對象只能調用const成員函數,不能調用非const函數

指針和const的用法

  1. 當const修飾指針時,由於const的位置不同,它的修飾對象會有所不同。
  2. int *const p2中const修飾p2的值,所以理解爲p2的值不可以改變,即p2只能指向固定的一個變量地址,但可以通過*p2讀寫這個變量的值。頂層指針表示指針本身是一個常量
  3. int const *p1或者const int *p1兩種情況中const修飾*p1,所以理解爲*p1的值不可以改變,即不可以給*p1賦值改變p1指向變量的值,但可以通過給p賦值不同的地址改變這個指針指向。底層指針表示指針所指向的變量是一個常量。
  4. int const *const p;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章