13、對象的構造函數
- 構造函數是一種特殊的成員函數。
- 構造函數不需要用戶調用,而是在建立對象時自動執行。
- 構造函數的名字必須與類名相同,而不能由用戶任意命名。
- 夠贊函數的功能是由用戶定義的,用戶根據初始化的要求設計函數體和函數參數。
14、不同對象執行析構函數的動機
- 對于函數中定義的自動局部對象,當函數被調用結束時,對象釋放,在對象釋放前自動執行析構函數。
- static局部對象只在main()函數結束或調用exit函數結束程序時,調用static局部對象的析構函數。
- 對于全局對象,在程序的流程離開其作用域時(如main函數結束或調用exit函數)時,調用該全局對象的析構函數。
- 只要對象的生命周期結束,程序就自動執行實現設計好的析構函數來完成相關工作。
15、派生類的構造函數和析構函數
- 派生類中由基類繼承而來的成員的初始化工作還是由基類的構造函數完成,派生類中新增的成員在派生類中構造函數中初始化。
- 如果基類中沒有不帶參數的構造函數,那么在派生類的構造函數中必須調用基類構造函數,以初始化積累成員。
- 派生類中構造函數的執行程序:
- 先執行基類構造函數,調用順序按照他們被繼承時聲明的順序。
- 再執行內嵌成員對象的構造函數,調用順序按照他們在類中聲明的順序。
- 最后執行派生類構造函數。
- 派生類析構函數的執行順序
- 先執行派生類的析構函數。
- 再執行內嵌成員對象的析構函數,調用順序按照他們在類中聲明的反順序。
- 再執行其基類的析構函數,調用順序按照他們被繼承時聲明的順序。
16、類的封裝
- 將有關的代碼和數據封裝在一個對象中,每個對象間相互獨立,互不干擾。
- 將對象中的某些部分對外隱蔽,隱蔽內部細節,只留下少量接口。
- 類具有信息隱藏的能力,能夠有效的把類的內部數據隱藏起來,使外部函數只有只有通過類的公有成員才能訪問類的內部數據。
- 封裝使類成為一個具有內部數據的自我隱藏能力,功能獨立的軟件模塊。
- 類的公有成員也稱為類的接口,外部函數要訪問類的內部成員,只有通過類的公有成員才能實現。
17、形參帶默認值的函數
- 給默認值的時候,從右向左給。
- 調用效率的問題。
- 定義出可以給形參默認值,聲明也可以給形參默認值形參給默認值的時候,不管是定義處給,還是聲明處給,形參默認值只能出現一次。
18、智能指針
- unique_ptr
- 表示互斥權,拷貝構造函數和拷貝賦值運算符都delete了。
- 一個unique_ptr擁有一個對象,在某一時刻,只能由一個unique_ptr指向一個給定的對象。當unique_ptr被銷毀,所致的對象也被銷毀。
- unique_ptr不能拷貝,不能賦值,可以移動。
- 為動態分配的內存提供異常安全,unique_ptr可以理解為一個簡單的指針(指向一個對象)或一對指針(包含釋放器deleter的情況)。
- 將動態分配內存的所有權傳遞給函數。
- 從函數返回動態分配的內存。
- shared_ptr:
- shared_ptr表示共享所有權,可以共享一個對象。當兩段代碼都沒有獨享所有權(負責銷毀對象)時,可以使用shared_ptr。shared_ptr是一種計數指針,當計數變為0時釋放所指向的對象。
- 其實就是一個指針套上了釋放器,套上了計數器,拷貝的時候增加了引用,賦值也增加了引用,相應的也會有遞減了引用計數。
- weak_ptr:
- 是一種不控制所指向對象生存期的智能指針,指向由一個shared_ptr管理的對象。
- weak_ptr,不影響shared_ptr的引用計數。一旦shared_ptr被銷毀,那么對象也會被銷毀,即使weak_ptr還指向這個對象,這個對象也會被銷毀。
- auto_ptr:
被 c++11 棄用,原因是缺乏語言特性如 “針對構造和賦值” 的 std::move
語義,以及其他瑕疵。
- auto_ptr 與 unique_ptr 比較
- auto_ptr 可以賦值拷貝,復制拷貝后所有權轉移;unqiue_ptr 無拷貝賦值語義,但實現了
move
語義; - auto_ptr 對象不能管理數組(析構調用
delete
),unique_ptr 可以管理數組(析構調用delete[]
);
- auto_ptr 可以賦值拷貝,復制拷貝后所有權轉移;unqiue_ptr 無拷貝賦值語義,但實現了
19、純虛函數和虛函數的區別
- 虛函數和純虛函數可以定義在同一個類中,含有純虛函數的類被稱為抽象類,而只含有虛函數的類不能被稱為抽象類。
- 虛函數可以直接被使用,也可以被子類重載以后以多態的形式調用,而純虛函數必須在子類中實現該函數才可以使用,因為純虛函數在基類只有聲明而沒有定義。
- 虛函數和純虛函數都可以在子類中被重載,以多態的形式被調用。
- 虛函數和純虛函數通常存在于抽象基類之中,被繼承的子類重載,目的是提供一個統一的接口。
- 虛函數和純虛函數的定義中不能有static標識符,被static修飾的函數在編譯時候要求前期綁定,然而虛函數卻是動態綁定,而且被兩者修飾的函數聲明周期也不一樣。
- 虛函數必須實現,如果不實現,編譯器將報錯。
- 虛函數,父類和子類都有各自的版本。由多態方式調用的時候動態綁定。
- 實現了純虛函數的子類,改純虛函數在子類中就變成了虛函數,子類的子類可以覆蓋。該虛函數,由多態方式調用的時候動態綁定
- 虛函數是C++中用于實現多態的機制。核心理念就是通過基類訪問派生類定義的。
- 包含純虛函數的類叫做抽象類(也稱為接口類),抽象類不能實例化處對象。
20、哈希函數
- 哈希沖突的產生原因:哈希是通過對數據進行再壓縮,提高效率的一種解決方法。但由于通過哈希函數產生的哈希值是有限的,而數據可能比較多,導致經過哈希函數處理后仍然有不同的數據對應相同的值。這時候就產生了哈希沖突。
- Hash哈希沖突發生的場景:當關鍵字值域遠大于哈希表的長度,而且事先并不知道關鍵字的具體取值時。hash沖突就會發生。
- Hash溢出發生的場景:當關鍵字的實際取值大于哈希表的長度時,而且表中已裝滿了記錄,如果插入一個新紀錄,不僅發生沖突,而且還會發生溢出。
解決哈希沖突的方法主要有:開放地址法和拉鏈法。
- 開放地址法:
- 線性探測:按順序決定值時,如果數據的值已經存在,則在原來值的基礎上往后加一個單位,直至不發生哈希沖突。
- 再平方探測:按順序決定值時,如果某數據的值已經存在,則在原來值的基礎上先加1的平方個單位,若仍然存在則減1的平方個單位。隨之是2的平方,3的平方等。直至不發生哈希沖突。
- 偽隨機探測:按順序決定值時,如果某數據已經存在,通過隨機函數隨機生成一個數,在原來值得基礎上加上隨機數,直至不發生哈希沖突。
- 鏈式地址法:
對于相同的值,使用鏈表進行連接。使用數組存儲每一個鏈表
- 優點:
- 拉鏈法處理沖突簡單,且無堆積現象,即非同義詞絕不會發生沖突,因此平均查找長度較短。
- 由于拉鏈中個鏈表的節點空間時動態申請的,故它更適合于造表前無法確定表長的情況。
- 開放定址法為減少沖突,要求裝填因子較小,故當節點規模較大時會浪費很多空間。而拉鏈法中可取a>=1,且節點較大時,拉鏈法中增加的指針域可忽略不計,因此節省空間。
- 再用拉鏈法構造的散列表中,刪除節點的操作易于實現,只要簡單地山區鏈表上相應的節點即可。
- 缺點:
- 指針占用較大空間時,會造成空間浪費,若空間用于增大散列表規模進而提高開放地址法的效率。
- 建立公共溢出區存儲所有哈希沖突的數據。
- 對于沖突的哈希值再次進行哈希處理,直至沒有哈希沖突。
21、C++強制轉換
- static_cast
- static_cast 用于進行比較“自然”和低風險的轉換,如整型和浮點型、字符型之間的互相轉換。另外,如果對象所屬的類重載了強制類型轉換運算符 T(如 T 是 int、int* 或其他類型名),則 static_cast 也能用來進行對象到 T 類型的轉換。
- static_cast 不能用于在不同類型的指針之間互相轉換,也不能用于整型和指針之間的互相轉換,當然也不能用于不同類型的引用之間的轉換。因為這些屬于風險比較高的轉換。
- reinterpret_cast
reinterpret_cast 用于進行各種不同類型的指針之間、不同類型的引用之間以及指針和能容納指針的整數類型之間的轉換。轉換時,執行的是逐個比特復制的操作。
- const_cast
const_cast 運算符僅用于進行去除 const 屬性的轉換,它也是四個強制類型轉換運算符中唯一能夠去除 const 屬性的運算符。
- dynamic_cast
用 reinterpret_cast 可以將多態基類(包含虛函數的基類)的指針強制轉換為派生類的指針,但是這種轉換不檢查安全性,即不檢查轉換后的指針是否確實指向一個派生類對象。dynamic_cast專門用于將多態基類的指針或引用強制轉換為派生類的指針或引用,而且能夠檢查轉換的安全性。對于不安全的指針轉換,轉換結果返回 NULL 指針。
22、構造函數為什么不能是虛函數
虛函數對應一個虛指針,虛指針其實是存儲在對象的內存空間的。如果構造函數是虛函數,就需要通過虛函數表中對應的虛函數指針(編譯期間生成屬于類)來調用,可對象目前還沒有實例化,也即是還沒有內存空間,何來的虛指針,所以構造函數不能是虛函數。
虛函數的作用在于通過父類的指針或者引用來調用它的成員函數的時候,能夠根據動態類型來調用子類相應的成員函數。而構造函數是在創建對象時自動調用的,不可能通過父類的指針或者引用去調用,所以構造函數不能是虛函數。
23、虛函數可以是內聯函數嗎
- 虛函數可以是內聯函數,內聯是可以修飾虛函數的,但是當虛函數表現多態性的時候不能內聯。
- 內聯是在編譯期建議編譯器內聯,而虛函數的多態性在運行期,編譯器無法知道運行期調用哪個代碼,因此虛函數表現為多態性時(運行期)不可以內聯。
inline virtual
唯一可以內聯的時候是:編譯器知道所調用的對象是哪個類(如Base::who()
),這只有在編譯器具有實際對象而不是對象的指針或引用時才會發生。
24、strcat、strcpy、strcmp區別
-
strcat函數原型char* strcat(char* dest,const char* src);
進行字符串的拼接,將第二個字符串連接到第一個字符串中第一個出現\\0開始的地方。返回的是拼接后字符的首地址。并不檢查第一個數組的大小是否可以容納第二個字符串。如果第一個數組的已分配的內存不夠容納第二個字符串,則多出來的字符將會溢出到相鄰的內存單元。
-
strncat函數原型:strncat(dest,src,maxsize)
功能跟strcat一致,不過它帶有一個maxsize的參數,設置容納的最大的字符長度。如在遇到\\0之前達到了最大字符長度,則會只連接最大字符長度個數的字符。
-
*strcpy函數原型 char strcpy(char dest,const char src);
將第二個字符串\\0之前的字符復制到第一個內存地址內。返回的是復制后的字符串的首地址。有char*返回值是為了函數能夠支持鏈式表達式,增加了函數的“附加值”。char a[7]="abcdef",char b[5]="xyz";
strcpy(a,b)函數 當將后面的數組賦值給前面那個時侯 除去五個元素后,從下標為5開始的元素仍舊是之前a[5]的元素。 -
strncpy(str1,str2,numbe)
是將str2中的前number個字符賦給str1,或是將\\0之前的字符賦給str1.
-
**strcmp函數原型 **int strcmp(const char src1,const char src2);
進行兩個字符串中從第一個開始的ASCII碼的比較 。遇到\\0或者不一致時退出,如果前者大于后者返回1,小于返回-1 如果在兩個中的任何一個的\\0之前都保持一致,則返回0. 當src或src遇到\\0時即停止比較.strcmp比較的是字符串,不是字符,字符之間的比較可以直接用==
-
strncmp(str1,str2,numbe)
函數在strcmp的基礎上多了一個int參數,即指定比較前幾個字符是否相等。
25、虛函數和靜態函數的區別
靜態函數在編譯時就已經確定,而虛函數在運行時動態綁定。虛函數是實現多態重要手段,在函數前加virtual關鍵字即可。
26、靜態函數與靜態變量的區別
- 類靜態數據成員在編譯時創建并初始化:在該類的任何對象建立之前就存在,不屬于任何對象,而非靜態類成員變量則是屬于對象所有的。類靜態數據成員只有一個拷貝,為所有此類的對象所共享。
- 類靜態成員函數屬于整個類,不屬于某個對象,由該類所有對象共享。
- static 成員變量實現了同類對象間信息共享。
- static 成員類外存儲,求類大小,并不包含在內。
- static 成員是命名空間屬于類的全局變量,存儲在 data 區的rw段。
- static 成員只能類外初始化。
- 可以通過類名訪問(無對象生成時亦可),也可以通過對象訪問。
27、public、protected、private區別
- public: 可以被該類中的函數、子類的函數、其友元函數訪問,也可以由該類的對象訪問。
- protected: 可以被該類中的函數、子類的函數、以及其友元函數訪問,但不能被該類的對象訪問。
- private: 只能由該類中的函數、其友元函數訪問,不能被任何其他訪問,該類的對象也不能訪問。
-
C++
+關注
關注
22文章
2108瀏覽量
73653 -
STL
+關注
關注
0文章
86瀏覽量
18327 -
面向對象
+關注
關注
0文章
64瀏覽量
9985
發布評論請先 登錄
相關推薦
評論