C++學習篇(2)

愛折騰的碼農發表於2021-01-02

更多精彩請關注微信公眾號“愛折騰的碼農”,二維碼見下圖。
在這裡插入圖片描述

本篇內容主要是分享指標和引用、c++型別轉換操作符等內容,我主要是也根據《More Effective C++》、《C++ primer》和一些面經進行總結的。

引用(reference

    定義:為另一個變數起了一個另外的名字(可以直接說變數的別名),通過宣告符寫成&refival的形式來定義引用型別,其中ival為宣告的變數名。

圖片

    對於變數別名的理解

圖片

 

引用變數和被引用變數並沒有共用一塊記憶體,引用變數其實是另外開闢了一塊記憶體;引用變數開闢的記憶體裡面存放的是被引用變數的地址;任何對引用變數的操作都會轉換為對解引用的操作,例如:(*refval)代表的就是ival。

    引用的注意事項

沒有空引用,即定義必須初始化;引用總是指向它最初獲得的那個物件,即引用將和它初始值物件一直繫結在一起,無法令引用再繫結其他物件。

    

    常量引用注意:​​​​​​​

非常量引用不能繫結在常量上常量引用既可以繫結在常量上也可以繫結在非常量上不能通過常量引用去改變被引用的值

    

    引用分類

圖片

 

左值:有名字,可以取地址,非臨時右值:沒有名字,不能取地址,臨時的(定義方式:型別 && 引用名 = 右值表示式)

    本篇重點講一下右值引用,因為這在面試中會經常被問到,比如說c++11特性、右值引用的特點。。。

    右值引用

    • 定義:指代臨時的物件,它們只在當前的語句中有效。

    • 目的:1、消除兩個物件之間不必要的拷貝,節省運算儲存資源,提高執行效率(轉移語義)2、能夠更簡潔明確的定義泛型程式設計(完美轉發)。

    • 轉移語義:將資源 ( 堆,系統物件等 ) 從一個物件轉移到另一個物件,這樣能夠減少不必要的臨時物件的建立、拷貝以及銷燬,能夠大幅度提高 C++ 應用程式的效能。臨時物件的維護 ( 建立和銷燬 ) 對效能有嚴重影響。

    • 完美轉發:在引數傳遞過程中屬性和引數值都不變

    • std::move:將左值引用轉換為右值引用,實現轉移語義。原理:摺疊引用。

圖片

 

圖片

 

        接下來就是分析指標和引用的區別。相信學習過c語言的人對指標並不陌生,其實指標就是一種儲存變數地址的變數。因為對於每個變數來說都有自己的地址,而指標就是儲存這個地址的變數。

圖片

      具體指標和引用區別如下,這裡面我只是舉了一些常見的內容,還有一些可以自行去網上百度,很多講的特別詳細。​​​​​​​

引用不需要解引用就可以直接獲取指向記憶體空間的值,而指標需要解引用;引用的賦值操作不需要取地址符來賦值,而是通過變數名;但是指標必須通過取地址符來實現;引用必須要初始化,且指向的地址不能被改變;但是指標就更加靈活,可以初始化為空或者不初始化;通過sizeof獲取大小不同,指標一般和作業系統位數有關,如32位的指標佔4個位元組,但是引用是引用物件所佔的大小;引用和指標自增結果不同;引用的底層是通過指標實現的;通過malloc/new申請記憶體的返回值是指標。

 

 

C++強制型別轉換

       下面說這一段其實主要是為了引出四種型別操作符,可看可不看,不過z在面試中可以簡單介紹一下為什麼會出現這四種型別操作符。

        對於C語言來說,它可能會隱式將一種型別轉換成其他型別(比如說使用malloc分配記憶體時,其首先返回void*,然後隱式轉換成相應型別的指標),但是這種轉換並不能夠精確的指明意圖。雖然其也提供了一些方式來進行顯示的轉換,比如說使用一對小括號加上一個物件名稱(標誌符)組成,如​​​​​​​

float fnum = 1.2;int num = (int)fnum;  //從float轉換成int

    由於小括號和物件名稱在C++中任何地方都可能被用到,因此為了解決這些問題,C++引入了4種新的型別轉換操作符,如下圖所示。

圖片

  • static_cast

    格式:static_cast<type>(expression)​​​​​​​

int firstNumber, secondNumber;...double result = static_cast<double>(firstNumber/ secondNumber)

    用途​​​​​​​

用於基本資料型別之間的轉換,如把int轉換成double用於類型別轉換,如派生類和基類之間,但是需要注意這種沒有型別安全檢查,即基類轉換成派生類可能會有問題。把空指標轉換成目標型別的指標

 

    注意

static_cast基本上擁有C就是轉型相同的威力和意義,以及相同的限制。例如,不能夠利用static_cast將一個struct轉換成int,或將一個double轉換成指標;另外,static_cast也不能去除表示式的常量性。因為有一個新式轉型操作符const_cast專司此職。

《More Effective C++》

    

    為什麼要用static_cast轉換而不用c語言中的轉換?​​​​​​​

更安全;更直接明顯,能夠一眼看出是什麼型別轉換成什麼型別,容易找出程式中的錯誤;可清楚地辨別程式碼中每個顯式的強制轉換;可讀性更好,容易被解析,且能體現程式設計師的意圖。(可看《More Effective c++》第二節)

 

  • const_cast

    格式:const_cast<type> (expression)

    用途

用來改變表示式中的常量性或易變性,即將某個物件的常量性去除掉

    注意:const_cast不是用於去除變數的常量性,而是去除指向常數物件的指標或引用的常量性,其去除常量性的物件必須為指標或引用。 

 

  • reinterpret_cast

    格式:reinterpret_cast<type> (expression),必須是一個指標、引用、算術型別、函式指標或者成員指標

    用途:改變指標或引用的型別、將指標或引用轉換為一個足夠長度的整形、將整型轉換為指標或引用型別。不過最常用的是轉換“函式指標”型別。

    注意:使用reinterpret_cast強制轉換過程僅僅是位元位的拷貝,因此需要特別謹慎
 

  • dynamic_cast

    格式:dynamic_cast<type> (expression)

   用途​​​​​​​

其他三種型別轉換都是編譯時完成的,dynamic_cast是執行時處理的,執行時要進行型別檢查;不能用於內建的基本資料型別的強制轉換;dynamic_cast轉換如果成功的話返回的是指向類的指標或引用,轉換失敗的話則會返回NULL或者丟擲異常;使用dynamic_cast進行轉換的,基類中一定要有虛擬函式,否則編譯不通過,但是static_cast沒有這方面要求。

    需要檢測虛擬函式的原因:1、類中存在虛擬函式,就說明它有想要讓基類指標或引用指向派生類物件的情況,此時轉換才有意義;2、執行時型別檢查需要執行時型別資訊儲存在類的虛擬函式表中,只有定義了虛擬函式的類才有虛擬函式表。  

圖片來自於網上截圖

 

    總結:對於引用部分,相信看面經的人知道問的機率挺多的,特別是右值引用。在回答的時候可以說一下右值引用和左值引用的區別、右值引用的作用、右值引用中轉移語義和完美轉發實現原理(其實就是摺疊引用),然後據一些例子;另外,對於指標和引用的區別,我覺得可以先說引用為什麼是變數的別名,接下來引出引用為什麼必須要初始化,以及與指標的其他區別;最後,對於c++型別轉換部分,可以分成編譯時處理和執行時完成兩類來講解這四種型別轉換,同時也要記得突出每種轉換操作符的重點以及侷限性,比如說const_cast主要去除常量性等等。以上只是本人的一些思路,具體還是要看個人情況而定。

相關文章