C/C++經典面試題
1, 變數的宣告和定義有什麼區別
為變數分配地址和儲存空間的稱為定義,不分配地址的稱為宣告。一個變數可以在多個地方宣告,但只能在一個地方定義。加入extern 修飾的是變數的宣告,說明此變數將在檔案以外或在檔案後面部分定義
說明:很多時候一個變數,只是宣告不分配記憶體空間,直到具體使用時才初始化,分配記憶體空間,如外部變數。
2, 寫出 bool int float 指標變數與零值比較的if語句
Bool型資料
If(flag)
If(!flag)
Int型資料:if(0!=flag)
If(0==flag)
指標型資料:if(NULL==flag)
If(NUJLL!=flag)
Float 型資料:
Define NORM 0.00001;if(flag>=-NORM && flag<=NORM)
注意:應特別注意在int,指標型變數和零值比較的時候,把零值放在左邊,這樣當把==誤寫成=時,編譯器可以報錯,否則這樣邏輯錯誤不容易發現,並且可能導致很嚴重的後果。
3, sizeof和strlen的區別
sizeof和strlen有一下區別:sizeof是一個運算子,strlen是庫函式
sizeof的引數可以使資料的型別,也可以是變數,而strlen只能是以‘\0’為結尾的字串作引數。
編譯器編譯是就計算出了sizeof的結果,而strlen函式必須在執行是才能計算出來。並且sizeof計算的是資料型別佔記憶體的大小,而strlen計算的是字串實際的長度
陣列做sizeof的引數不退化,傳遞strlen就退化成為指標了。
注意:有些運算子看起來像是函式,而有些函式名看起來又像運算子,這類容易混淆的名稱一定要加以區分,否則遇到陣列名這類特殊資料型別做引數時就很容易出錯。最容易混淆為函式的運算子就是sizeof。
4,
C語言的關鍵字static和c++的關鍵字static有什麼區別
在c中static用來修飾區域性靜態變數和外部靜態變數,函式。而c++中除了上述功能外,還用來定義類的成員變數和函式,即靜態成員變數和靜態成員函式
注意:程式設計時static的記憶性,和全域性性的特點可以讓在不同時期呼叫的函式進行通訊,傳遞資訊,而c++的靜態成員則可以在多個物件例項間進行通訊,傳遞資訊。
5.c中的malloc和c++中的new有什麼區別
Malloc和new有一下不同:new,delete是運算子,可以過載,只能在c++中使用
Malloc,free是函式,可以覆蓋,c,c++中都可以使用
New可以呼叫物件的建構函式,對應的delete呼叫相應的解構函式
Malloc僅僅分配記憶體,free僅僅回收記憶體,並不執行建構函式和解構函式
New delete返回的是某種資料型別指標,malloc free返回的是void指標
注意:malloc申請的記憶體空間要用free釋放,而new申請的記憶體空間要用delete釋放,不要混淆,因為兩者實現的機理不同
6,寫一個標準的宏MIN
#define min(a,b)((a)<=(b)?(a):(b))
注意:在呼叫時一定要注意這個宏定義的副作用,如下呼叫
(++*p)<(x)?(++*p):(x)
P指標就自加了兩次,違背了MIN的本意。
7,一個指標可以使volatile嗎
8,a和&a有什麼區別
請寫出以下程式碼的列印結果,主要目的是考察a和&a的區別
#include<stdlo.h>
Void main()
{
Int a[5]={1,2,3,4,5};
Int *ptr=(int *)(&a+1);
Printf(“%d,%d”,(a+1),*(ptr-1));
Return ;
}
輸出結果:2,5
注意:陣列名a可以作陣列的首地址,而&a是陣列的指標。
思考,將原式的int* ptr=(int *)(&a+1);
該為int *ptr=(int *)(a+1)時輸出的結果將是什麼呢
9,簡述C,C++程式編譯的記憶體分配情況
C,C++中記憶體分配方式可以分為三種:(1)從靜態儲存區域分配:記憶體在程式編譯時就已經分配好,這塊記憶體在程式的整個執行期間都存在,速度快,不容出錯,因為有系統會善後,例如,全域性變數,static變數等
(2)在棧上分配:在執行函式時,函式內區域性變數的儲存單元都在棧上建立,函式在執行結束時這些儲存單元自動被釋放,棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3)從堆上分配:即動態記憶體分配,程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由程式設計師決定,使用非常靈活,如果在堆上分配了空間,就有責任回收它,否則執行的程式會出現記憶體洩露,另外頻繁地分配和釋放不同大小的堆空間將會產生堆內碎片。
一個C,C++程式編譯時記憶體分為5大儲存區:堆區,棧區,全域性區,文字常量區,程式程式碼區
10,簡述strcpy,sprintf與memecpy的區別
三者主要有以下不同之處
(1) 操作物件不同:strcpy的兩個操作物件均為字串,sprintf的操作物件可以是多種資料型別,目的操作物件是字串,memcpy的兩個物件是兩個任意可操作的記憶體地址,並不限於何種資料型別。
(2) 執行功能不同:strcpy主要實現字串變數間的複製,sprintf主要實現其他資料型別格式到字串型別的轉化,memcpy主要是記憶體塊間的複製
(3) 執行效率不同:memcpy最高,sprintf最低
說明:strcpy,sprintf,memcpy都可以實現複製的功能,但是針對的物件不同,根據實際需求,來選擇合適的函式實現複製功能
11,設定地址為ox67a9的整形變數的值為oxaa66
Int *ptr;
Ptr=(int *)ox67a9;
*ptr=oxaa66;
說明:這道題就是強制型別轉換的典型例子,無論在什麼平臺地址長度和整型資料的長度是一樣的,即一個整型資料可以強制轉換成地址指標型別,只要有意義即可。
12,面向物件的三大特徵:面向物件的三大特徵是封裝性,繼承性,多型性。//有待完善
13.C++的空類有哪些成員函式
(1)預設的建構函式
(2)預設的複製建構函式
(3)預設的解構函式
(4)預設的賦值運算子
(5)預設取址運算子
(6)預設取址運算子const
注意:有些書上只是簡單的介紹了前四個函式,沒有提及後面兩個函式,但後兩個函式也是空類的預設函式。另外西藥注意的是,只有當實際使用這些函式的時候,編譯器才會定義他們。
14,談談你對複製建構函式和賦值運算子的認識
複製建構函式和複製運算子過載有以下兩個不同之處:(1)複製建構函式生成新的類物件,而賦值運算不能
(2)由於複製 建構函式是直接構造一個新的類物件,所以在初始化這個物件之前不用檢驗源物件是否和新建物件相同,而賦值運算子則需要這個操作,另外賦值運算子中如果原來的物件中記憶體非配要先把記憶體釋放掉
注意:當類中 有指標型別的成員變數時,一定要重寫複製建構函式和賦值運算子,不要使用預設的。
17:簡述類成員函式的重寫,過載和隱藏的區別
(1) 重寫和過載主要有以下幾點不同:範圍區別:被重寫的和重寫的函式在兩個類中,而過載和被過載的函式在同一個類中
引數的區別:被重寫的函式和重寫的函式的引數列表一定相同,而被過載函式和過載函式的引數列表一定不同
Virtual的區別:重寫的基類中被重寫的函式必須要有virtual修飾,而過載函式和被過載函式可以被virtual修飾,也可以沒有。
(2)隱藏和重寫,過載有以下幾點不同:
與過載的範圍不同,和重寫一樣,隱藏函式和被隱藏函式不在同一個類中
引數的區別:隱藏函式和被隱藏的函式的引數列表可以相同,也可以不同,但是函式名肯定要相同。當引數不相同是,無論基類中的引數是否被virtual修飾,基類的函式都是被隱藏,而不是被重寫。
說明:雖然過載和覆蓋都是實現多型的基礎,但是兩者實現的技術完全不同,達到的目的也是完全不同的,覆蓋是動態繫結的多型,而過載是靜態繫結的多型
18簡述多型實現的原理
編譯器發現一個類中有虛擬函式,便會立即為此類生成虛擬函式表vtable,虛擬函式表的各表項為指向對應虛擬函式的指標,編譯器還會在此類中隱含插入一個指標vptr(對vc編譯器來說,它插在類中的第一個位置上)指向虛擬函式表,呼叫此類的建構函式時,編譯器會隱含執行vptr與vtable的關聯程式碼,將vptr指向對應的vtable,將類與此類的vtable聯絡起來,另外在呼叫類的建構函式時,指向基類的指標此時已經變成指向具體的類的this指標,這樣依靠此this指標即可得到正確的vtable,如此才能真正與函式體進行連線,這就是動態聯編,實現多型的基本原理。
注意:一定要區分虛擬函式,純虛擬函式,虛擬繼承的關係和區別。牢記虛擬函式實現原理,因為多型C++面試的重要考點之一,而虛擬函式是實現多型的基礎。
19,連結串列和陣列有什麼區別
陣列和連結串列有以下幾點不同:(1)儲存形式:陣列是一塊連續的空間,宣告時就要確定長度,連結串列是一塊不連續的動態空間,長度可變,每個結點要儲存相鄰結點的指標。
(2) 資料查詢:陣列的線性查詢速度快,查詢操作直接使用偏移地址,連結串列需要按順序檢索結點,效率低
(4) 越界問題:連結串列不存在越界問題,陣列有越界問題
20,怎麼吧一個單鏈表反序
21,簡述佇列和棧的異同
注意:區別棧區和堆區,堆區的存取是順序隨意,而棧區是後進先出,棧由編譯器自動分配,存放函式的引數值,區域性變數的值等,其操作方式類似資料結構中的棧,堆一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回收,分配方式類似於連結串列
它與本題的的堆和棧是兩回事,堆疊只是一種資料結構,而堆區和棧區是程式中的不同記憶體儲存區域
22-28各種排序演算法
29談談你對程式設計規範的理解或認識
程式設計規範可總結為:程式的可行性,可讀性,可移植性,以及可測試性
說明:這是程式設計規範的總綱目,面試者不一定要去背誦上面給出的那幾個例子,應該去理解這幾個例子說明的問題,想一想,自己如何解決可行性,可讀性,可移植性,以及可測試性這幾個問題,結合上幾個例子和自己平時的程式設計習慣來回答這個問題
30 short i=0;i=i+1L; 這兩句有錯嗎
程式碼一是錯的,程式碼二十正確的
說明:在資料安全的情況下,大型別的資料向小型別的資料轉換一定要顯示的強制型別轉換
31,&& 和& ,||和|有什麼區別
(1)&和|對運算元進行求值運算,&&和||是判斷邏輯關係
(2)&&和|| 在判斷左運算元就能確定結果的情況下就不再對右運算元求值。
注意:在程式設計的時候有些時候將&& 或||替換成&和 |沒有出錯,但是其邏輯是錯誤的,可能導致不可預測的後果。
32C++的引用和c語言的指標有什麼區別
指標和引用主要有一下區別:(1)引用必須被初始化,但是不分配儲存空間,指標在宣告時初始化,在初始化的時候需要分配儲存空間。
(2)引用初始化以後不能被改變,指標可以改變所指向的物件
(3)不存在指向空值的引用,但存在指向空值的指標
注意:引用作為函式的引數時,會引發一定的問題,因為讓引用做引數,目的就是想改變這個引用所指向地址的內容,而函式呼叫時傳入的是實參,看不出函式的引數是正常變數還是引用,因此可能會引發錯誤,所以使用時一定要小心。
33,適當的資料結構為更好的演算法設計提供了有利的條件
35typedef和define有什麼區別
(1) 用法不同:typedef用來定義一種資料型別的別名,增強程式的可讀性,define主要用來定義常量,以及書寫複雜使用頻繁的宏
(2) 執行時間不同,typedef是編譯過程的一部分,有型別檢查得功能,define是宏定義,是預編譯的步部分,起發生在編譯之前,只是簡單的進行字串的替換,不進行型別的檢查
(3) 作用域不同:typedef有作用域限定,define不受作用域約束,只要define聲明後的引用都是正確的。
(4) 對指標的操作不同,typedef和define定義的指標時有很大的區別
(5) 注意:typedef定義是語句,因為句尾要加分號,而define不是語句,千萬不能在句尾加分號。
36關鍵字const是什麼
Const用來定義一個只讀的變數或物件。主要優點:便於型別檢查,同宏定義一樣可以方便的進行引數的修改和調整,節省空間,避免不必要的記憶體分配、可為函式過載提供引數。
說明:const修飾函式引數,是一種程式設計規範的要求,便於閱讀,一看即知這個引數不能被改變,實現時不易出錯
37static有什麼作用
Static在c中主要用於定義全域性靜態變數,定義區域性靜態變數,定義靜態函式,在c++中新增了兩個作用,定義靜態資料成員,定義靜態函式成員
注意:因為static定義的變數分配在靜態區,所以其定義的變數的預設值為0,普通的變數的預設值為隨機數,在定義指標變數時要特別注意。
Extern有什麼作用
Extern標識的變數或函式宣告起定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找定義
39流運算子過載為什麼返回引用
在程式中,流運算子>>和<<經常連續使用,因此這兩個運算子的返回值應該是一個仍舊支援這兩個運算子的流引用,其他的資料型別都無法做到這一點。
注意:出來在複製運算子和流運算子之外的其他的一些運算子中,如+-*/卻千萬不能返回引用,因為這死者運算子的物件都是右值,因此他們必須構造一個物件作為返回值。
40,簡述指標常量與常量指標區別
指標常量是指定義了一個指標,這個指標的值只能在定義時初始化,其他地方不能改變,常量指標是指定義了一個指標,這個指標指向一個只讀的物件,不能透過常量指標來改變這個物件的值。
指標常量強調的是指標的不可改變性,而常量指標強調的是指標對其所指物件的不可改變性
注意:無論是指標常量還是常量指標,其最大的用途就是作為函式的形式引數,保證實參在被呼叫函式中的不可改變性。
41陣列和指標的區別,即字元陣列和字串指標的區別
42如何避免“野指標”
野指標產生原因及解決辦法如下:(1)指標變數宣告時沒有被初始化,解決辦法:指標宣告時初始化,可以是具體的地址值,也可以是讓他指向NULL
(2)指標p被free或者delete之後,沒有置為NULL。解決辦法:指標指向的記憶體空間被釋放後指標應該指向NULL
(3)指標操作超越了變數的作用範圍,解決辦法:在變數的作用域結束前釋放掉變數的地址空間,並讓指標指向NULL
注意:野指標的解決方法也是程式設計規範的基本原則,平時使用指標時一定要避免產生野指標,在使用指標前一定要檢驗指標的合法性
43常引用有什麼作用
常引用的引入主要是為了避免使用變數的引用時,在不知道的情況下改變變數的值,常引用主要用於定義一個普通變數的只讀屬性的別名,作為函式的傳入引數,避免實參在呼叫函式中被意外的改變。
說明:很多情況下,需要用常引用做形參,被引用物件等效於常物件,不能在函式中改變實參的值,這樣的好處是有較高的易讀性和較小的出錯率。
49,建構函式能否為虛擬函式
建構函式不能是虛擬函式,而且不能在建構函式中呼叫虛擬函式,因為那樣實際執行的是父類的對應的函式,因為自己還沒有構造好,解構函式可以是虛擬函式,而且在一個複雜類結構中,這往往是必須的。解構函式也可以是純虛擬函式,但純虛擬函式必須有定義體,因為解構函式的呼叫是在子類中隱含的。說明:虛擬函式的動態繫結特性是 實現過載的關鍵技術,動態繫結根據實際的呼叫情況查詢相應類的虛擬函式表,呼叫相應的虛擬函式。
50談談你對面向物件的認識
面向物件可以理解成對待每一個問題,都是首先要確定這個問題由幾個部分組成,而每一個部分其實就是一個物件,然後再分別設計這些物件,最後得到整個程式,傳統的程式設計多是基於功能的思想來進行考慮和設計的,而面向物件的程式設計則是基於物件的角度來考慮問題的。這樣做能夠是得程式更加簡潔清晰。
說明:程式設計中接觸最多的面向物件程式設計技術僅僅是面向物件技術中的一個組成部分,發揮面向物件技術的優勢是一個綜合的技術問題,不僅僅需要面向物件的分析,設計和程式設計技術,而且需要藉助必要的建模和開發工具。
C/C++經典面試題
1, 變數的宣告和定義有什麼區別
為變數分配地址和儲存空間的稱為定義,不分配地址的稱為宣告。一個變數可以在多個地方宣告,但只能在一個地方定義。加入extern 修飾的是變數的宣告,說明此變數將在檔案以外或在檔案後面部分定義
說明:很多時候一個變數,只是宣告不分配記憶體空間,直到具體使用時才初始化,分配記憶體空間,如外部變數。
2, 寫出 bool int float 指標變數與零值比較的if語句
Bool型資料
If(flag)
If(!flag)
Int型資料:if(0!=flag)
If(0==flag)
指標型資料:if(NULL==flag)
If(NUJLL!=flag)
Float 型資料:
Define NORM 0.00001;if(flag>=-NORM && flag<=NORM)
注意:應特別注意在int,指標型變數和零值比較的時候,把零值放在左邊,這樣當把==誤寫成=時,編譯器可以報錯,否則這樣邏輯錯誤不容易發現,並且可能導致很嚴重的後果。
3, sizeof和strlen的區別
sizeof和strlen有一下區別:sizeof是一個運算子,strlen是庫函式
sizeof的引數可以使資料的型別,也可以是變數,而strlen只能是以‘\0’為結尾的字串作引數。
編譯器編譯是就計算出了sizeof的結果,而strlen函式必須在執行是才能計算出來。並且sizeof計算的是資料型別佔記憶體的大小,而strlen計算的是字串實際的長度
陣列做sizeof的引數不退化,傳遞strlen就退化成為指標了。
注意:有些運算子看起來像是函式,而有些函式名看起來又像運算子,這類容易混淆的名稱一定要加以區分,否則遇到陣列名這類特殊資料型別做引數時就很容易出錯。最容易混淆為函式的運算子就是sizeof。
4,
C語言的關鍵字static和c++的關鍵字static有什麼區別
在c中static用來修飾區域性靜態變數和外部靜態變數,函式。而c++中除了上述功能外,還用來定義類的成員變數和函式,即靜態成員變數和靜態成員函式
注意:程式設計時static的記憶性,和全域性性的特點可以讓在不同時期呼叫的函式進行通訊,傳遞資訊,而c++的靜態成員則可以在多個物件例項間進行通訊,傳遞資訊。
5.c中的malloc和c++中的new有什麼區別
Malloc和new有一下不同:new,delete是運算子,可以過載,只能在c++中使用
Malloc,free是函式,可以覆蓋,c,c++中都可以使用
New可以呼叫物件的建構函式,對應的delete呼叫相應的解構函式
Malloc僅僅分配記憶體,free僅僅回收記憶體,並不執行建構函式和解構函式
New delete返回的是某種資料型別指標,malloc free返回的是void指標
注意:malloc申請的記憶體空間要用free釋放,而new申請的記憶體空間要用delete釋放,不要混淆,因為兩者實現的機理不同
6,寫一個標準的宏MIN
#define min(a,b)((a)<=(b)?(a):(b))
注意:在呼叫時一定要注意這個宏定義的副作用,如下呼叫
(++*p)<(x)?(++*p):(x)
P指標就自加了兩次,違背了MIN的本意。
7,一個指標可以使volatile嗎
8,a和&a有什麼區別
請寫出以下程式碼的列印結果,主要目的是考察a和&a的區別
#include<stdlo.h>
Void main()
{
Int a[5]={1,2,3,4,5};
Int *ptr=(int *)(&a+1);
Printf(“%d,%d”,(a+1),*(ptr-1));
Return ;
}
輸出結果:2,5
注意:陣列名a可以作陣列的首地址,而&a是陣列的指標。
思考,將原式的int* ptr=(int *)(&a+1);
該為int *ptr=(int *)(a+1)時輸出的結果將是什麼呢
9,簡述C,C++程式編譯的記憶體分配情況
C,C++中記憶體分配方式可以分為三種:(1)從靜態儲存區域分配:記憶體在程式編譯時就已經分配好,這塊記憶體在程式的整個執行期間都存在,速度快,不容出錯,因為有系統會善後,例如,全域性變數,static變數等
(2)在棧上分配:在執行函式時,函式內區域性變數的儲存單元都在棧上建立,函式在執行結束時這些儲存單元自動被釋放,棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3)從堆上分配:即動態記憶體分配,程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由程式設計師決定,使用非常靈活,如果在堆上分配了空間,就有責任回收它,否則執行的程式會出現記憶體洩露,另外頻繁地分配和釋放不同大小的堆空間將會產生堆內碎片。
一個C,C++程式編譯時記憶體分為5大儲存區:堆區,棧區,全域性區,文字常量區,程式程式碼區
10,簡述strcpy,sprintf與memecpy的區別
三者主要有以下不同之處
(1) 操作物件不同:strcpy的兩個操作物件均為字串,sprintf的操作物件可以是多種資料型別,目的操作物件是字串,memcpy的兩個物件是兩個任意可操作的記憶體地址,並不限於何種資料型別。
(2) 執行功能不同:strcpy主要實現字串變數間的複製,sprintf主要實現其他資料型別格式到字串型別的轉化,memcpy主要是記憶體塊間的複製
(3) 執行效率不同:memcpy最高,sprintf最低
說明:strcpy,sprintf,memcpy都可以實現複製的功能,但是針對的物件不同,根據實際需求,來選擇合適的函式實現複製功能
11,設定地址為ox67a9的整形變數的值為oxaa66
Int *ptr;
Ptr=(int *)ox67a9;
*ptr=oxaa66;
說明:這道題就是強制型別轉換的典型例子,無論在什麼平臺地址長度和整型資料的長度是一樣的,即一個整型資料可以強制轉換成地址指標型別,只要有意義即可。
12,面向物件的三大特徵:面向物件的三大特徵是封裝性,繼承性,多型性。//有待完善
13.C++的空類有哪些成員函式
(1)預設的建構函式
(2)預設的複製建構函式
(3)預設的解構函式
(4)預設的賦值運算子
(5)預設取址運算子
(6)預設取址運算子const
注意:有些書上只是簡單的介紹了前四個函式,沒有提及後面兩個函式,但後兩個函式也是空類的預設函式。另外西藥注意的是,只有當實際使用這些函式的時候,編譯器才會定義他們。
14,談談你對複製建構函式和賦值運算子的認識
複製建構函式和複製運算子過載有以下兩個不同之處:(1)複製建構函式生成新的類物件,而賦值運算不能
(2)由於複製 建構函式是直接構造一個新的類物件,所以在初始化這個物件之前不用檢驗源物件是否和新建物件相同,而賦值運算子則需要這個操作,另外賦值運算子中如果原來的物件中記憶體非配要先把記憶體釋放掉
注意:當類中 有指標型別的成員變數時,一定要重寫複製建構函式和賦值運算子,不要使用預設的。
17:簡述類成員函式的重寫,過載和隱藏的區別
(1) 重寫和過載主要有以下幾點不同:範圍區別:被重寫的和重寫的函式在兩個類中,而過載和被過載的函式在同一個類中
引數的區別:被重寫的函式和重寫的函式的引數列表一定相同,而被過載函式和過載函式的引數列表一定不同
Virtual的區別:重寫的基類中被重寫的函式必須要有virtual修飾,而過載函式和被過載函式可以被virtual修飾,也可以沒有。
(2)隱藏和重寫,過載有以下幾點不同:
與過載的範圍不同,和重寫一樣,隱藏函式和被隱藏函式不在同一個類中
引數的區別:隱藏函式和被隱藏的函式的引數列表可以相同,也可以不同,但是函式名肯定要相同。當引數不相同是,無論基類中的引數是否被virtual修飾,基類的函式都是被隱藏,而不是被重寫。
說明:雖然過載和覆蓋都是實現多型的基礎,但是兩者實現的技術完全不同,達到的目的也是完全不同的,覆蓋是動態繫結的多型,而過載是靜態繫結的多型
18簡述多型實現的原理
編譯器發現一個類中有虛擬函式,便會立即為此類生成虛擬函式表vtable,虛擬函式表的各表項為指向對應虛擬函式的指標,編譯器還會在此類中隱含插入一個指標vptr(對vc編譯器來說,它插在類中的第一個位置上)指向虛擬函式表,呼叫此類的建構函式時,編譯器會隱含執行vptr與vtable的關聯程式碼,將vptr指向對應的vtable,將類與此類的vtable聯絡起來,另外在呼叫類的建構函式時,指向基類的指標此時已經變成指向具體的類的this指標,這樣依靠此this指標即可得到正確的vtable,如此才能真正與函式體進行連線,這就是動態聯編,實現多型的基本原理。
注意:一定要區分虛擬函式,純虛擬函式,虛擬繼承的關係和區別。牢記虛擬函式實現原理,因為多型C++面試的重要考點之一,而虛擬函式是實現多型的基礎。
19,連結串列和陣列有什麼區別
陣列和連結串列有以下幾點不同:(1)儲存形式:陣列是一塊連續的空間,宣告時就要確定長度,連結串列是一塊不連續的動態空間,長度可變,每個結點要儲存相鄰結點的指標。
(2) 資料查詢:陣列的線性查詢速度快,查詢操作直接使用偏移地址,連結串列需要按順序檢索結點,效率低
(4) 越界問題:連結串列不存在越界問題,陣列有越界問題
20,怎麼吧一個單鏈表反序
21,簡述佇列和棧的異同
注意:區別棧區和堆區,堆區的存取是順序隨意,而棧區是後進先出,棧由編譯器自動分配,存放函式的引數值,區域性變數的值等,其操作方式類似資料結構中的棧,堆一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回收,分配方式類似於連結串列
它與本題的的堆和棧是兩回事,堆疊只是一種資料結構,而堆區和棧區是程式中的不同記憶體儲存區域
22-28各種排序演算法
29談談你對程式設計規範的理解或認識
程式設計規範可總結為:程式的可行性,可讀性,可移植性,以及可測試性
說明:這是程式設計規範的總綱目,面試者不一定要去背誦上面給出的那幾個例子,應該去理解這幾個例子說明的問題,想一想,自己如何解決可行性,可讀性,可移植性,以及可測試性這幾個問題,結合上幾個例子和自己平時的程式設計習慣來回答這個問題
30 short i=0;i=i+1L; 這兩句有錯嗎
程式碼一是錯的,程式碼二十正確的
說明:在資料安全的情況下,大型別的資料向小型別的資料轉換一定要顯示的強制型別轉換
31,&& 和& ,||和|有什麼區別
(1)&和|對運算元進行求值運算,&&和||是判斷邏輯關係
(2)&&和|| 在判斷左運算元就能確定結果的情況下就不再對右運算元求值。
注意:在程式設計的時候有些時候將&& 或||替換成&和 |沒有出錯,但是其邏輯是錯誤的,可能導致不可預測的後果。
32C++的引用和c語言的指標有什麼區別
指標和引用主要有一下區別:(1)引用必須被初始化,但是不分配儲存空間,指標在宣告時初始化,在初始化的時候需要分配儲存空間。
(2)引用初始化以後不能被改變,指標可以改變所指向的物件
(3)不存在指向空值的引用,但存在指向空值的指標
注意:引用作為函式的引數時,會引發一定的問題,因為讓引用做引數,目的就是想改變這個引用所指向地址的內容,而函式呼叫時傳入的是實參,看不出函式的引數是正常變數還是引用,因此可能會引發錯誤,所以使用時一定要小心。
33,適當的資料結構為更好的演算法設計提供了有利的條件
35typedef和define有什麼區別
(1) 用法不同:typedef用來定義一種資料型別的別名,增強程式的可讀性,define主要用來定義常量,以及書寫複雜使用頻繁的宏
(2) 執行時間不同,typedef是編譯過程的一部分,有型別檢查得功能,define是宏定義,是預編譯的步部分,起發生在編譯之前,只是簡單的進行字串的替換,不進行型別的檢查
(3) 作用域不同:typedef有作用域限定,define不受作用域約束,只要define聲明後的引用都是正確的。
(4) 對指標的操作不同,typedef和define定義的指標時有很大的區別
(5) 注意:typedef定義是語句,因為句尾要加分號,而define不是語句,千萬不能在句尾加分號。
36關鍵字const是什麼
Const用來定義一個只讀的變數或物件。主要優點:便於型別檢查,同宏定義一樣可以方便的進行引數的修改和調整,節省空間,避免不必要的記憶體分配、可為函式過載提供引數。
說明:const修飾函式引數,是一種程式設計規範的要求,便於閱讀,一看即知這個引數不能被改變,實現時不易出錯
37static有什麼作用
Static在c中主要用於定義全域性靜態變數,定義區域性靜態變數,定義靜態函式,在c++中新增了兩個作用,定義靜態資料成員,定義靜態函式成員
注意:因為static定義的變數分配在靜態區,所以其定義的變數的預設值為0,普通的變數的預設值為隨機數,在定義指標變數時要特別注意。
Extern有什麼作用
Extern標識的變數或函式宣告起定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找定義
39流運算子過載為什麼返回引用
在程式中,流運算子>>和<<經常連續使用,因此這兩個運算子的返回值應該是一個仍舊支援這兩個運算子的流引用,其他的資料型別都無法做到這一點。
注意:出來在複製運算子和流運算子之外的其他的一些運算子中,如+-*/卻千萬不能返回引用,因為這死者運算子的物件都是右值,因此他們必須構造一個物件作為返回值。
40,簡述指標常量與常量指標區別
指標常量是指定義了一個指標,這個指標的值只能在定義時初始化,其他地方不能改變,常量指標是指定義了一個指標,這個指標指向一個只讀的物件,不能透過常量指標來改變這個物件的值。
指標常量強調的是指標的不可改變性,而常量指標強調的是指標對其所指物件的不可改變性
注意:無論是指標常量還是常量指標,其最大的用途就是作為函式的形式引數,保證實參在被呼叫函式中的不可改變性。
41陣列和指標的區別,即字元陣列和字串指標的區別
42如何避免“野指標”
野指標產生原因及解決辦法如下:(1)指標變數宣告時沒有被初始化,解決辦法:指標宣告時初始化,可以是具體的地址值,也可以是讓他指向NULL
(2)指標p被free或者delete之後,沒有置為NULL。解決辦法:指標指向的記憶體空間被釋放後指標應該指向NULL
(3)指標操作超越了變數的作用範圍,解決辦法:在變數的作用域結束前釋放掉變數的地址空間,並讓指標指向NULL
注意:野指標的解決方法也是程式設計規範的基本原則,平時使用指標時一定要避免產生野指標,在使用指標前一定要檢驗指標的合法性
43常引用有什麼作用
常引用的引入主要是為了避免使用變數的引用時,在不知道的情況下改變變數的值,常引用主要用於定義一個普通變數的只讀屬性的別名,作為函式的傳入引數,避免實參在呼叫函式中被意外的改變。
說明:很多情況下,需要用常引用做形參,被引用物件等效於常物件,不能在函式中改變實參的值,這樣的好處是有較高的易讀性和較小的出錯率。
49,建構函式能否為虛擬函式
建構函式不能是虛擬函式,而且不能在建構函式中呼叫虛擬函式,因為那樣實際執行的是父類的對應的函式,因為自己還沒有構造好,解構函式可以是虛擬函式,而且在一個複雜類結構中,這往往是必須的。解構函式也可以是純虛擬函式,但純虛擬函式必須有定義體,因為解構函式的呼叫是在子類中隱含的。說明:虛擬函式的動態繫結特性是 實現過載的關鍵技術,動態繫結根據實際的呼叫情況查詢相應類的虛擬函式表,呼叫相應的虛擬函式。
50談談你對面向物件的認識
面向物件可以理解成對待每一個問題,都是首先要確定這個問題由幾個部分組成,而每一個部分其實就是一個物件,然後再分別設計這些物件,最後得到整個程式,傳統的程式設計多是基於功能的思想來進行考慮和設計的,而面向物件的程式設計則是基於物件的角度來考慮問題的。這樣做能夠是得程式更加簡潔清晰。
說明:程式設計中接觸最多的面向物件程式設計技術僅僅是面向物件技術中的一個組成部分,發揮面向物件技術的優勢是一個綜合的技術問題,不僅僅需要面向物件的分析,設計和程式設計技術,而且需要藉助必要的建模和開發工具。