考研复试专业课面试——C++
記:此篇博客是關于考研復試中專業課面試的相關知識點,按個人理解以及網上查資料來總結的,用來鍛煉自己的邏輯思維,可能不太準確,希望指正。
1、什么是虛函數和純虛函數?
? ? 基類指針可以指向其公有派生類對象,但當用基類指針訪問其指向的派生類對象時只能訪問該派生類從基類繼承而來的對象而不能訪問該派生類中定義的對象,此時就需要虛函數來解決這個問題。
? ? ?虛函數是在基類中用virtual關鍵字說明并在派生類中被重新定義的成員函數,引入數函數的目的是為了動態綁定。引入純虛函數的目的是為了派生接口,即在基類中為其派生類保留一個函數接口,以便于其派生類根據自己的需要進行重新定義。純虛函數沒有函數體,不具備函數功能,不能被調用。聲明純虛函數時令其等于0只是起到一個形式上的作用,并不代表其返回值為0,若一個類至少包含一個純虛函數,則稱該類為抽象類。
2、基類為什么要有虛析構函數?
? ? 如果沒有虛析構函數,在銷毀一個由基類指針指向的派生類對象時,只能調用基類的析構函數而不能調用派生類的析構函數,導致派生類對象所申請的空間無法釋放而造成內存泄漏,此時就可以通過定義虛析構函數,以便通過基類指針銷毀派生類對象。
3、當i是一個整數時,i++和++i哪一個更快?他們的區別是什么?
? ? 當i是一個整數時,他們基本一樣快。他們的區別在于:i++是先使用變量i,再使i的值加1,而++i是先使i的值加1,再使用i。也就是說i++返回的是i的值,而++i返回的是i+1的值。
4、指針和引用的區別?
? ? 指針和引用的本質區別在于:指針是一個新的變量,只不過這個變量存儲的是另一個變量的地址,可以通過該地址即指針變量來訪問原來的變量,這種方式成為間接訪問,需要用間接運算符*。引用只是另一個變量的別名,它和原本的變量擁有相同的地址,對引用的操作即是對該變量的操作,這種訪問方式稱為直接訪問,不需要間接運算符,所以使用引用可以簡化操作。
? ? 指針在做為函數參數時,內部是值傳遞,指針的值是不能改變的,要通過解引用才能夠對原變量進行操作。引用在做函數參數時,內部傳遞的實際是變量的地址。
5、static關鍵字的作用?
? ? 修飾局部變量:局部變量本來存儲在動態區,被static修飾后為靜態變量,改變了其存儲位置,存儲在靜態區。其生命周期與程序相同,在main函數之前初始化,在程序退出時銷毀。
? ? 修飾全局變量:全局變量本來就存儲在靜態區,所以static修飾并不能改變其存儲位置,但是可以改變其作用域,只有包含該變量定義的文件才能訪問。
? ? 修飾函數:static修飾函數作用也是改變其作用域,至于包含該函數定義的文件才能調用。對于靜態函數來說,其聲明和定義應該在同一個文件中。
? ? 修飾成員變量:static修飾的類成員變量是類的全局變量,被該類的所有對象所共有,包括派生類對象,即所有的對象都只維持同一個實例。所以static修飾的成員變量要在類外進行初始化,而不能在類內初始化。
? ? 修飾成員函數:static修飾的成員函數是該類所有對象所共享的函數,使這個類只存在這一個函數,沒有this指針且被static修飾的成員函數只能訪問static成員變量。靜態成員可以獨立訪問,即不必創建對象即可進行訪問。
? ? 當同時編譯多個文件時,非static的全局變量或函數都是具有全局可見性的,也可以被其他的源文件來訪問。對于函數來講,static修飾只是起到了限制其作用域的作用。
6、為什么static和const不能同時修飾成員函數?
? ? c++編譯器在實現const的成員函數時為了使其不改變類的實例的狀態,就添加了參數const this*,但當聲明一個static成員函數時是不存在this指針的,也就是二者的用法是相沖突的。
7、const的作用?
? ? const可以用來定義變量使其為只讀變量,不能做修該,使用const修飾的變量一定要進行初始化。const還可修飾函數的參數或返回值。
? ? const成員函數:也就是在成員函數的參數列表后面添加const關鍵字,const成員函數可以訪問const的成員變量和非const的成員變量,但是不能修改任何變量。因此,在聲明成員函數時,如果該函數不對數據成員做修改操作,則可能把其聲明為const成員函數。
? ? const對象只能訪問const成員函數不能訪問非const成員函數,非const對象可以訪問任意成員函數,包括const成員函數。
8、C++的多態性?
? ? 多態性可以簡單的概括為“一個接口,多種方法”,分為編譯時多態性和運行時多態性,編譯時多態性通過重載函數(重載)實現,運行時多態性通過虛函數(重寫)實現。重載要求函數名相同但函數的參數列表不相同,重寫要求函數名,函數類型,函數參數列表都相同。
? ? 多態和非多態的區別就是函數地址是早綁定還是晚綁定。如果函數調用在編譯時就能確定函數的調用地址則是靜態的,即函數地址是早綁定,若函數調用在編譯時不能確定函數的調用地址需要在運行時才能確定則是動態的,即函數地址是晚綁定。
? ? 常見的用法是聲明基類的指針,用該指針指向派生類對象,調用相應的虛函數,根據指針指向的派生類對象的不同而實現不同的方法。
9、面向對象和面向過程的區別?
? ? 面向過程:是分析出解決問題的步驟,然后用函數一步一步實現這些步驟,在使用時就依次調用函數。優點是:比面向對象的性能高,因為類需要實例化,開銷比較大,比較消耗資源,缺點是:沒有面向對象易擴展,易維護,易復用。
? ? 面向對象:是把要解決的問題劃分成各個對象,建立對象的目的是為了描述某個事物在整個問題解決步驟中的行為。優點是:易維護,易復用,易擴展,因為面向對象具有封裝、繼承和多態性,可以設計出低耦合的系統,使系統更加靈活,易于維護。缺點是:性能較低。
10、C和C++的區別?
? ? C語言是面向過程的語言,是結構化的語言,考慮如何通過一個過程對輸入進行處理得到輸出。C++是面向對象的語言,考慮如何根據具體問題域建立一個合適的對象模型,具有“封裝、繼承和多態”的特性。封裝隱藏了實現細節,使代碼模塊化;派生類繼承父類的方法和數據,擴展原有的模塊,實現了代碼的復用;多態性是“一個接口,多個方法”,通過派生類重寫父類的虛函數,實現接口的復用。
? ? c語言用malloc和free動態管理內存,不支持函數重載,沒有引用;c++用new和delete動態管理內存,支持函數重載,有引用的概念。?
11、虛函數表是針對類的還是針對對象的?同一個類的兩個對象的虛函數表是怎么維護的?
? ? 編譯器為一個類維護一個虛函數表,每個對象的首地址保存著該虛函數表的指針,同一個類的不同對象指向同一張虛函數表。在類內部添加一個指向該虛函數表的指針,該虛函數表保存所有對象的虛函數入口地址,可以根據此虛函數表找到自己的函數的入口,每個類的虛函數表都不一樣。對于純虛函數來說,相當于一個占位符,純虛函數在虛函數表中占一個位置,當派生類實現后再把真正的函數指針填進去。
12、內聯函數和宏定義的區別?const和#define的區別?
? ? 宏定義是在預編譯時把所有的宏名用宏體來替換,簡單來說就是字符串的替換。內聯函數是在編譯時進行代碼插入,在調用內聯函數的地方直接把內聯函數的內容展開,省去了函數調用時的壓棧和出棧操作,提高了效率。內聯函數是嵌入代碼,在調用函數時不進行跳轉而是把內聯函數的代碼插入到相應位置。內聯函數在編譯時要進行參數類型檢查,因此內聯函數更安全、可靠,但這是犧牲空間來換取的性能提升。
? ? const是在編譯時替換,define是在預處理的時候替換;define沒有類型,不進行類型檢查,const有類型,要進行類型檢查。
13、堆和棧的區別?
? ? 管理方式:棧是由編譯器自動管理而堆需要手動釋放。
? ? 增長方向:棧向下增長,以降序分配存儲空間;堆是向上增長,以升序分配存儲空間
? ? 是否產生碎片:進棧和出棧都是按照順序依次進行的,不會產生碎片;堆要頻繁的進行new和delete,造成存儲空間不連續,易產生碎片。
? ? 分配方式:棧能夠進行動態分配也能靜態分配;堆只能進行動態分配。
? ? 分配效率:棧是系統提供的數據結構,計算機在底層對其進行支持,進棧和出棧都有專門的指令;堆是由c或c++函數庫提供的,且機制比較復雜,棧的效率比堆的效率要高,但是卻沒有堆靈活。
14、c++中類與結構體的區別?
? ? 最大的區別就是默認訪問控制,struct作為數據結構的實現體,其默認的數據訪問控制為public,class作為類的實現體,其默認的成員訪問控制為private的。并且class可以用于定義模板參數,類似于typename,而struct則不能定義模板參數。
15、析構函數的作用?
? ? 析構函數用于釋放定義的對象的指針,默認的析構函數不是顯示調用的,自定義的析構函數要進行顯示調用。
? ? 當類里面只用到了基本數據類型,如int double等時,系統的默認析構函數不進行任何操作;當用到如vector和string等數據類型時,會自己調用系統默認的析構函數。
? ? 如果是自定義的析構函數,且占用了內存空間等資源時,在程序結束時需要調用自定義的析構函數來釋放掉占用的資源,防止內存泄漏。
16、操作系統和編譯器如何區分全局變量和局部變量?
? ? 操作系統只管進程調度,編譯器根據變量存儲空間的分配位置來判斷,全局變量分配在全局數據段(靜態存儲區)并在程序運行前加載,局部變量分配在(動態存儲區)棧中。
17、結構體和聯合體的區別?
? ? 結構體和聯合體都是由不同類型的數據成員所構成的,聯合體中在某一個時間點只能有一個變量成員存在,所有的變量成員共享一段內存空間,對聯合體不同成員賦值時會對其他成員進行重寫,其他成員的值就不存在了。結構體中在某一個時間點所有變量成員均存在,且所有變量的內存地址不同,對結構體的成員賦值時是不會產生相互影響的。
18、重載和重寫的區別?
? ? 從定義上來說:重載時允許存在多個同名函數,但這些函數的參數表不同(可能是參數個數不同,可能是參數類型不同,可能兩者都不相同),重寫是子類對父類中的虛函數重新定義。
? ? 從實現原理上來說:重載時編譯器根據函數不同的參數表,對函數的名稱進行處理,使這些同名函數成為不同的函數。重寫是當子類對父類虛函數進行重新定義后,父類指針根據賦給其不同的子類指針,動態的調用該子類的函數,在編譯時不能確定調用的是哪個函數。
19、有關純虛函數的理解?
? ? 純虛函數是為你的程序制定的一種標準,它只是一個接口,需要在子類中進行實現,且純虛函數沒有函數體,不具備函數功能,不能被調用。包含純虛函數的類為抽象類,這種類不能直接生成對象,需要在子類中重寫虛函數之后才能夠使用。
? ? 虛函數是為了繼承接口和默認行為,實現動態綁定。純虛函數只是為了繼承接口,行為必須重新定義。
20、內存溢出、內存泄漏的原因?
? ? 內存溢出是指在申請內存空間時出現沒有足夠的內存空間供其使用的情況,內存溢出的原因大致有如下4種:
? ? (1) 內存中加載的數據量過于龐大,例如一次從數據庫中取較多的數據
? ? (2) 代碼中出現死循環或者循環產生過多重復的對象實體
? ? (3) 遞歸調用的層次太深導致堆棧溢出
? ? (4) 內存泄漏導致內存溢出
? ? 內存泄漏是指在向系統申請了內存空間等資源,在使用完畢后沒有進行資源釋放,而造成占用有效內存。
21、為什么要聲明虛基類?
? ? 在當基類被多個子類繼承時,在這些繼承路徑的匯合處基類會產生多個實例,從而導致二義性。如果想要這個基類只產生一個實例供所有子類共享使用,則要用virtual關鍵字把該公共基類聲明為虛基類。
22、c++文件編譯與執行的四個階段?
? ? (1)根據文件中的預處理指令來修改源文件
? ? (2)編譯成匯編代碼
? ? (3)將匯編代碼翻譯成機器指令
? ? (4)鏈接目標代碼生成可執行程序
23、定義和聲明的區別?
? ? 變量聲明:用于告訴程序變量的類型和名字
? ? 變量定義:為變量分配內存空間,還可以為變量賦初值,變量有且只有一個定義。在變量定義的同時也是聲明了變量的類型和名字。
? ? extern關鍵字:用extern關鍵字是聲明變量而不是定義變量。
24、c++內存分配的方式?
? ? (1)在靜態存儲區分配內存,編譯時分配,在程序運行的整個期間都存在
? ? (2)在棧中分配內存,系統自動進行分配和釋放,例如局部變量就是在棧中分配內存空間
? ? (3)在堆中分配內存,需要程序員手動進行分配和釋放,并指定大小。
? ? 棧可以進行動態分配和靜態分配,而堆只能夠進行動態分配,棧的效率比堆的高但沒有堆靈活。
25、繼承體系下同名成員函數的關系?
? ? (1)重載:在同一作用域,函數名相同,參數列表不同,返回值類型可以相同也可以不相同
? ? (2)重寫:在不同的作用域(分別在父類和子類),函數名相同,參數列表相同,返回值類型相同,基類的函數需要有virtual關鍵字聲明。
? ? (3)重定義:在不同的作用域(分別在父類和子類),函數名相同,在父類和派生類中只要不符合重寫的均是重定義
26、什么情況下會調用拷貝構造函數(三種情況)?
? ? 類會自動生成構造函數:普通構造函數和拷貝構造函數,當生成一個普通的類對象的時候會自動調用普通構造函數,當用一個類對象去初始化另一個對象時會調用拷貝構造函數;
? ? 調用拷貝構造函數的三種情況:
? ? (1)當用一個類的對象去初始化另一個新的對象時
? ? (2)當函數的參數為類的對象且為值傳遞的時候,當為引用時不會調用
? ? (3)當函數的返回值為類的對象或者引用的時候
27、虛函數是怎么實現的?
? ? 每一個含有虛函數的類都有一個虛函數表,虛函數表中保存著該類的所有虛函數的函數指針(地址),類的實例對象不包含虛函數表,只有虛函數指針。
?
c++到此就更新完畢了~
?
總結
以上是生活随笔為你收集整理的考研复试专业课面试——C++的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看携程如何借助“预测式外呼”提高呼叫效率
- 下一篇: Linux部署Oracle11gR2 R