C++面向对象基础(二)
面向對象基礎
能夠準確理解下面這些問題是從C程序員向C++程序員進階的基礎。當然了,這只是一部分。
面向對象三大特性?
-
封裝性:數據和代碼捆綁在一起,避免外界干擾和不確定性訪問。
-
繼承性:讓某種類型對象獲得另一個類型對象的屬性和方法。
-
多態性:同一事物表現出不同事物的能力,即向不同對象發送同一消息,不同的對象在接收時會產生不同的行為(重載實現編譯時多態,虛函數實現運行時多態)。
public/protected/private的區別?
-
public的變量和函數在類的內部外部都可以訪問。
-
protected的變量和函數只能在類的內部和其派生類中訪問。
-
private修飾的元素只能在類內訪問。
對象存儲空間?
-
非靜態成員的數據類型大小之和。
-
編譯器加入的額外成員變量(如指向虛函數表的指針)。
-
為了邊緣對齊優化加入的padding。(內存對齊)
C++空類有哪些成員函數?
-
首先,空類大小為1字節。
-
默認函數有:
-
構造函數
-
析構函數
-
拷貝構造函數
-
賦值運算符
-
構造函數能否為虛函數,析構函數呢?
-
析構函數:
-
析構函數可以為虛函數,并且一般情況下基類析構函數要定義為虛函數。
-
只有在基類析構函數定義為虛函數時,調用操作符delete銷毀指向對象的基類指針時,才能準確調用派生類的析構函數(從該級向上按序調用虛函數),才能準確銷毀數據。
-
析構函數可以是純虛函數,含有純虛函數的類是抽象類,此時不能被實例化。但派生類中可以根據自身需求重新改寫基類中的純虛函數。
-
-
構造函數:
- 構造函數不能定義為虛函數。在構造函數中可以調用虛函數,不過此時調用的是正在構造的類中的虛函數,而不是子類的虛函數,因為此時子類尚未構造好。
構造函數調用順序,析構函數呢?
-
調用所有虛基類的構造函數,順序為從左到右,從最深到最淺
-
基類的構造函數:如果有多個基類,先調用縱向上最上層基類構造函數,如果橫向繼承了多個類,調用順序為派生表從左到右順序。
-
如果該對象需要虛函數指針(vptr),則該指針會被設置從而指向對應的虛函數表(vtbl)。
-
成員類對象的構造函數:如果類的變量中包含其他類(類的組合),需要在調用本類構造函數前先調用成員類對象的構造函數,調用順序遵照在類中被聲明的順序。
-
派生類的構造函數。
-
析構函數與之相反。
構造的時候先調用基類的構造函數,再調用派生類的構造函數
析構的時候先調用派生類的析構函數,再調用基類的析構函數
?
拷貝構造函數中深拷貝和淺拷貝區別?
-
深拷貝時,當被拷貝對象存在動態分配的存儲空間時,需要先動態申請一塊存儲空間,然后逐字節拷貝內容。
-
淺拷貝僅僅是拷貝指針字面值。
-
當使用淺拷貝時,如果原來的對象調用析構函數釋放掉指針所指向的數據,則會產生空懸指針。因為所指向的內存空間已經被釋放了。
拷貝構造函數和賦值運算符重載的區別?
-
拷貝構造函數是函數,賦值運算符是運算符重載。
-
拷貝構造函數會生成新的類對象,賦值運算符不能。
-
拷貝構造函數是直接構造一個新的類對象,所以在初始化對象前不需要檢查源對象和新建對象是否相同;賦值運算符需要上述操作并提供兩套不同的復制策略,另外賦值運算符中如果原來的對象有內存分配則需要先把內存釋放掉。
-
形參傳遞是調用拷貝構造函數(調用的被賦值對象的拷貝構造函數),但并不是所有出現"="的地方都是使用賦值運算符,如下:
Student s;Student s1 = s; // 調用拷貝構造函數Student s2;s2 = s; // 賦值運算符操作
注:類中有指針變量時要重寫析構函數、拷貝構造函數和賦值運算符
虛函數和純虛函數區別?
-
虛函數是為了實現動態編聯產生的,目的是通過基類類型的指針指向不同對象時,自動調用相應的、和基類同名的函數(使用同一種調用形式,既能調用派生類又能調用基類的同名函數)。虛函數需要在基類中加上virtual修飾符修飾,因為virtual會被隱式繼承,所以子類中相同函數都是虛函數。當一個成員函數被聲明為虛函數之后,其派生類中同名函數自動成為虛函數,在派生類中重新定義此函數時要求函數名、返回值類型、參數個數和類型全部與基類函數相同。
-
純虛函數只是相當于一個接口名,但含有純虛函數的類不能夠實例化。(抽象基類,類似于Java中的接口)
覆蓋、重載和隱藏的區別?
-
覆蓋是派生類中重新定義的函數,其函數名、參數列表(個數、類型和順序)、返回值類型和父類完全相同,只有函數體有區別。派生類雖然繼承了基類的同名函數,但用派生類對象調用該函數時會根據對象類型調用相應的函數。覆蓋只能發生在類的成員函數中。(運行時多態)
-
隱藏是指派生類函數屏蔽了與其同名的函數,這里僅要求基類和派生類函數同名即可。其他狀態同覆蓋。可以說隱藏比覆蓋涵蓋的范圍更寬泛,畢竟參數不加限定。
-
重載是具有相同函數名但參數列表不同(個數、類型或順序)的兩個函數(不關心返回值),當調用函數時根據傳遞的參數列表來確定具體調用哪個函數。重載可以是同一個類的成員函數也可以是類外函數。(編譯時多態)
在main執行之前執行的代碼可能是什么?
- 全局對象的構造函數。
哪幾種情況必須用到初始化成員列表?
-
初始化一個const成員。
-
初始化一個reference成員。
-
調用一個基類的構造函數,而該函數有一組參數。
-
調用一個數據成員對象的構造函數,而該函數有一組參數。
什么是虛指針?
-
虛指針或虛函數指針是虛函數的實現細節。
-
虛指針指向虛表結構。
重載和函數模板的區別?
-
重載需要多個函數,這些函數彼此之間函數名相同,但參數列表中參數數量和類型不同。在區分各個重載函數時我們并不關心函數體。
-
模板函數是一個通用函數,函數的類型和形參不直接指定而用泛型來代表。但只適用于參數個數相同而類型不同的函數。
this指針是什么?
-
this指針是類的指針,指向對象的首地址。
-
this指針只能在成員函數中使用,在全局函數、靜態成員函數中都不能用this。
-
this指針只有在成員函數中才有定義,且存儲位置會因編譯器不同有不同存儲位置。
類模板是什么?(STL就是一種實現)
-
用于解決多個功能相同、數據類型不同的類需要重復定義的問題。
-
在建立類時候使用template及任意類型標識符T,之后在建立類對象時,會指定實際的類型,這樣才會是一個實際的對象。
-
類模板是對一批僅數據成員類型不同的類的抽象,只要為這一批類創建一個類模板,即給出一套程序代碼,就可以用來生成具體的類。
構造函數和析構函數調用時機?
-
全局范圍中的對象:構造函數在所有函數調用之前執行,在主函數執行完調用析構函數。
-
局部自動對象:建立對象時調用構造函數,離開作用域時調用析構函數。
-
動態分配的對象:建立對象時調用構造函數,調用釋放時調用析構函數。
-
靜態局部變量對象:建立時調用一次構造函數,主函數結束時調用析構函數。
總結
以上是生活随笔為你收集整理的C++面向对象基础(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++基础汇总(一)
- 下一篇: 构造函数不可以声明为虚函数,析构函数可以