C 面試題精髓
#1.##、為什麼建構子不能聲明為虛函數?
解析:因為虛函數採用的是虛擬呼叫的方法,虛呼叫是指允許在只知道部分資訊的情況下的工作機制,特別允許我們呼叫一個只知道介面而不知道其物件的準確類型的函數。 但是如果我們要呼叫建構函式建立物件時,必須要知道物件的準確類型,因此建構函式不能為虛擬函式。2.C #中哪些函數不能被宣告為虛函數?
解析:普通函數(非成員函數),建構函數,內聯成員函數、靜態成員函數、友元函數。 (1)虛擬函數用於基底類別和衍生類,普通函數所以不能(2)建構函數不能是因為虛函數採用的是虛擬呼叫的方法,(3)內聯成員函數的實質是在呼叫的地方直接將程式碼擴展開(4)繼承時,靜態成員函數不能被繼承的,它只屬於一個類,因為也不存在動態聯編(5)友元函數不是類別的成員函數,因此也不能被繼承
3 .類別的靜態成員和非靜態成員有何不同?
答案:類別的靜態成員每個類別只有一個,靜態成員為所有類別的實例物件共享,靜態成員有靜態成員變數和靜態成員函數,靜態成員變數使用前必須初始化,靜態成員變數可以被靜態成員函數和非靜態成員函數訪問,而靜態成員函數只能存取靜態成員變量,因為靜態成員函數屬於類,其沒有this指標。非靜態成員每個物件都有一個。4 重載(overload)和重寫(overried,有的書也叫做「覆蓋」)的差別?
重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數型別不同,或許兩者都不同)。 重寫:是指子類別重新定義複類別虛函數的方法。 從實作原理上來說:重載:編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然後這些同名函數就成了不同的函數(至少對編譯器來說是這樣的)。如,有兩個同名函數:function func(p:integer):integer;和function func(p:string):integer;。那麼編譯器做過修飾後的函式名稱可能是這樣的:int_func、str_func.對於這兩個函式的調用,在編譯器間就已經確定了,是靜態的。也就是說,它們的位址在編譯期就綁定了(早期綁定),因此,重載和多態無關! 重寫:和多態有真實相關。當子類重新定義了父類的虛擬函數後,父類指針根據賦給它的不同的子類指針,動態的調用屬於子類的該函數,這樣的函數調用在編譯期間是無法確定的(調用的子類別的虛擬函數的位址無法給出)。因此,這樣的函數位址是在運行期綁定的(晚綁定)5 簡述成員函數、全域函數和友元函數的差異。
成員函數只能由該類別所實例化的物件來進行呼叫。 [靜態成員除外] 全域函數可以在任意位置進行呼叫。 友元函數可以讓本類別和友元類別物件呼叫。 用new分配的記憶體用delete刪除用new[]分配的記憶體用delete[]刪除delete[]會呼叫數組元素的析構函數。內部資料型別沒有析構函數,所以問題不大。如果你在用delete時沒用括號,delete就會認為指向的是單一對象,否則,它就會認為指向的是一個陣列。6.繼承的優缺點。
類別繼承是在編譯時刻靜態定義的,且可直接使用,類別繼承可以較方便地改變父類別的實作。但是類別繼承也有一些不足之處。首先,因為繼承在編譯時刻就定義了,所以無法在執行時刻改變從父類別繼承的實作。更糟的是,父類別通常至少定義了子類別的部分行為,而父類別的任何改變都可能影響子類別的行為。如果繼承下來的實作不適合解決新的問題,則父類別必須重寫或被其他更適合的類別取代。這種依賴關係限制了靈活性並最終限制了復用性。 (待補充)
7.C 有哪些性質(物件導向特點)
##封裝,繼承和多態。 在物件導向程式設計語言中,封裝是利用可重複使用成分建構軟體系統的特性,它不僅支援系統的可重用性,而且還有利於提高系統的可擴充性;訊息傳遞可以實現發送一個通用的訊息而呼叫不同的方法;封裝是實現資訊隱藏的一種技術,其目的是使類別的定義和實作分離。8. 什麼時候需要使用「常引用」?
如果要利用引用來提高程式的效率,也要保護傳遞給函數的資料不在函數中改變,就 應使用常引用。常引用宣告方式:const 類型識別碼 &引用名=目標變數名稱;int a const int &ra=a; ra=1; //錯誤a=1; //正確 例2 string foo( ); void bar(string & s); 那麼以下的表達式式將是非法的: bar(foo( )); bar("hello world"); 原因在於foo( )和"hello world"串串都會產生一個臨時對象,而在C 中,這些臨時對像都是const類型的。因此上面的表達式就是試圖將一個const類型的物件轉換為非const類型,這是非法的。引用型參數應該在能定義為const的情況下,盡量定義為const#9.ASSERT()是做什麼用的
#答案:ASSERT()是一個調試程式時常用的宏,在程式執行時它計算括號內的表達式,如果表達式為FALSE (0), #程序將報告錯誤,並終止執行。如果表達式不為0,則繼續執行後面的語句。這個巨集通常原來判斷程式中是否出現了明顯非法的數據,如果出現了終止程序以免導致嚴重後果,同時也便於查找錯誤。例如,變數n在程式中不應該為0,如果為0可能導致錯誤,10. ##實作多態的方法? 解析: ① 一個基底類別的參考可以指向它的衍生類別實例
② 一個基底類別的指標實例
11. 物件導向的三個基本特徵,並且簡單敘述之? ① 封裝:將客觀事物抽象化成類,每個類別對自身的資料和方法實行存取控制(private, protected,public)
# ② 繼承:廣義的繼承有三種實作形式:
實作繼承(指使用基底類別的屬性和方法而無需額外編碼的能力)
視覺繼承(子窗體使用父窗體的外觀和實作程式碼)
介面繼承(僅使用屬性和方法,實作滯後到子類別實作)。
前兩種(類別繼承)和後者(物件組合=>介面繼承以及純虛函數)構成了功能復用的兩種方式。
③ 多態:是將父物件設定為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據目前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類別類型的指標賦值給父類別類型的指標。
補充問題: 多態性的功能?
主要是兩個:
1. 隱藏實作細節,使得程式碼能夠模組化;擴充程式碼模組,實作程式碼重複使用;
2. 介面重用:為了類在繼承和衍生的時候,保證使用家族中任一類別的實例的某一屬性時的正確呼叫。
12# 重載(overload)和重寫(overried,有的書也叫做「#「覆蓋
」
)的差別?
① 重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數型別不同,或許兩者都不同)。 ② 重寫:是指子類別重新定義父類別虛函數的方法。 從實作原理上來說:① 重載:編譯器依照函數不同的參數表,對同名函數的名稱做修飾,然後這些同名函數就成了不同的函數(至少對於編譯器來說是這樣的)。對於這類函數的調用,在編譯期間就已經確定了,是靜態的。也就是說,它們的位址在編譯期就綁定了(早期綁定),因此,重載和多態無關! ② 重寫:和多型態真正相關。當子類重新定義了父類的虛擬函數後,父類指針根據賦給它的不同的子類指針,動態的調用屬於子類的該函數,這樣的函數調用在編譯期間是無法確定的(調用的子類別的虛擬函數的位址無法給出)。因此,這樣的函數位址是在運行期間綁定的(晚綁定)
#13
多態的作用? 主要是兩個:① 隱藏實作細節,使得程式碼能夠模組化;擴充程式碼模組,實作程式碼重複使用;② 介面重複使用:為了類別在繼承和衍生的時候,保證使用家族中任一類別的實例的某一屬性時的正確呼叫。
14#、C 中的空類,預設產生的類別成員函數:
class { public: Empty(); // 缺省构造函数 Empty(const Empty&); // 拷贝构造函数 ~Empty(); // 析构函数 Empty& operator=(const Empty&); // 赋值运算符 Empty* operator&(); // 取值运算符 const Empty* operator&() const; // 取值运算符const };
15#.進程間通訊的方式有? 進程間通訊的方式有 :共享內存, 管道(有名管道/無名管道),Socket ,訊息佇列 ,訊號,信號量,記憶體映射等。
16
#死鎖的四個必要條件? 互斥,請求維持,不可剝奪,環路。
17
#、類別的靜態成員和非靜態成員有什麼不同?
類別的靜態成員每個類別只有一個,即是屬於本類別的;類別的非靜態成員每個物件都有一份。
18什麼是淺拷貝?什麼是深拷貝?
############ ###淺拷貝是指來源物件與拷貝物件共用一份實體,僅是引用的變數不同(名稱不同)。對其中任何一個物件的改變都會影響另外一個物件。 ############深拷貝是指來源物件與拷貝物件互相獨立,其中任何一個物件的改變都不會對另外一個物件造成影響。 ######一般來說,淺拷貝就是複製那個物件的指標。深拷貝就是複製了那個物件。
19、Window
s程式執行緒同步的幾種方式? (重要)
原子鎖定、臨界區(段)、事件、互斥(體)、信號量、可等待計時器
20什麼是「引用」?申明和使用「引用」要注意哪些問題? #答案:引用就是某個目標變數的「別名」(alias),對引用的運算與變數直接運算效果完全相同。申明一個引用的時候,切記要對其進行初始化。引用聲明完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,不能再把該引用名作為其他變數名的別名。宣告一個引用,不是新定義了一個變量,它只表示該引用名是目標變數名的一個別名,它本身不是一種資料類型,因此引用本身不佔儲存單元,系統也不給引用分配儲存單元。不能建立數組的引用。 21
#. 「引用」與指標的差異是什麼? #指標透過某個指標變數指向一個物件後,對它所指向的變數間接運算。程式中使用指針,程式的可讀性差;而引用本身就是目標變數的別名,而對引用的操作就是對目標變數的操作。另外,就是上面提到的對函數傳ref和pointer的差別。 22
#. 關聯、聚合(Aggregation)以及組合(Composition)的差異?#涉及UML中的一些概念:關聯是表示兩個類別的一般性聯繫,例如「學生」和「老師」就是一種關聯關係;聚合表示has-a的關係,是一種相對鬆散的關係,聚合類別不需要對被聚合類別負責,如下圖所示,用空的菱形表示聚合關係:
#從實現的角度講,聚合可表示為:
class A {...} class B { A* a; .....}#而組合表示contains-a的關係,關聯性強於聚合:組合類別與被組合類別有相同的生命週期,組合類別要對被組合類別負責,採用實心的菱形表示組合關係:實作的形式是:class A{ ...} class B{ A a; ...}23
.方面物件的三個基本特徵,並簡單敘述之?1. 封裝:將客觀事物抽象化成類,每個類別對自身的資料和方法實行protection(private, protected,public)# 2. 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承(僅使用屬性和方法,實作滯後到子類別實作)。前兩種(類別繼承)和後者(物件組合=>介面繼承以及純虛函數)構成了功能重複使用的兩種方式。 3. 多態:是將父物件設定為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據目前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類別類型的指標賦值給父類別類型的指標。 24
#多態的作用? 主要是兩個:1. 隱藏實作細節,使得程式碼能夠模組化;擴充程式碼模組,實作程式碼重複使用;2. 介面重複使用:為了類別在繼承和派生的時候,保證使用家族中任一類別的實例的某一屬性時的正確呼叫。 25
#############在C 程式中呼叫被C編譯器編譯後的函數,為什麼要加extern “C”聲明? ############//extern是C/C 語言中表明函數和全域變數作用範圍的關鍵字,該關鍵字告訴編譯器,其宣告的函數和變數可以在本模組或其它模組中使用
// extern 「C是連接申明,編譯時告訴編譯器以下程式碼以C風格的方式編譯與連接,其目的是實現C 與C及其它語言的混合程式設計。
指標透過某個指標變數指向物件後,對它所指向的變數間接操作。程式中使用指標,程式的可讀性差;而引用本身就是目標變數的別名,對引用的運算就是對目標變數的運算。此外,就是上面提到的對函數傳ref和pointer的差別。
#24 成員函數被重載的特徵:
(1)相同的範圍(同一個類別);
(2)函數名字相同;
(3)參數不同;
25覆蓋是指派生類別函數覆寫基底類別函數,特徵是:
(1)不同的範圍(分別位於衍生類別與基底類別);
(2)函數名字相同;
(3)參數相同;
26如果用VC開發程序,常見這麼幾個錯誤,C2001,c2005 ,c2011, 這些錯誤的原因是什麼。
在學習VC 的過程中,遇到的LNK2001錯誤的錯誤訊息主要為:unresolved external symbol “symbol”(不確定的外部“符號”)。 如果連接程式不能在所有的庫和目標文件內找到所引用的函數、變數或標籤,將產生此錯誤訊息。 一般來說,錯誤發生的原因有二:一是所引用的函數、變數不存在、拼字不正確或使用錯誤; 其次可能使用了不同版本的連接庫。 程式設計中常常能遇到LNK2005錯誤-重複定義錯誤,其實LNK2005錯誤並不是很難解決的錯誤.## #27介紹STL,詳細說明STL如何實作vector。
STL (標準模版庫,Standard Template Library)它由容器演算法迭代器組成。
STL有以下的一些優點:
可輕鬆實現搜尋資料或對資料排序等一系列的演算法;
調試程式時更安全且方便;
即使是人們用STL在UNIX平台下寫的程式碼你也可以很容易地理解(因為STL是跨平台的)。
vector實質上是動態數組,會根據資料的增加,動態的增加陣列空間。
28#介紹範本和容器。如何實現? (也許會讓你當場舉例實現)
模板可以說是比較古老了,但是目前的泛型程式實質上就是模板程式設計。
它體現了一種通用和泛化的想法。
STL有7種主要容器:vector,list,deque,map,multimap,set,multiset.
29 :簡述多型實作的原則
#編譯器發現一個類別中有虛函數,就會立即為此類產生虛函數表vtable。虛函數表的各表項為指向對應虛函數的指標。編譯器也會在此類中隱含插入一個指標vptr(對vc編譯器來說,它插在類的第一個位置上)指向虛擬函數表。當呼叫此類的建構子時,在類別的建構子中,編譯器會隱含執行vptr與vtable的關聯程式碼,將vptr指向對應的vtable,將類別與此類的vtable聯繫了起來。另外在呼叫類別的建構子時,指向基礎類別的指針此時已經變成指向具體的類別的this指針,這樣依賴此this指標即可得到正確的vtable,。如此才能真正與函數體連接,這就是動態聯編,實現多型態的基本原理。
30:談談你對物件導向的認知
解析:物件導向可以理解成對待每一個問題,都是首先要確定這個問題由幾個部分組成,而每一個部分其實就是一個物件。然後再分別設計這些對象,最後得到整個程式。傳統的程式設計多是基於功能的想法來進行考慮和設計的,而物件導向的程式設計則是基於物件的角度來考慮問題。這樣做能夠使得程式更加的簡潔清晰。
說明:程式設計中接觸最多的「物件導向程式設計技術」#僅僅是物件導向技術中的一個組成部分。發揮物件導向技術的優勢是一個綜合的技術問題,不僅需要物件導向的分析,設計和程式設計技術,而且需要藉助必要的建模和開發工具。
31 C 中為什麼要用模板類別。
解析:
1) 可用於建立動態成長與減少的資料結構
2) 它是型別無關的,因此具有很高的可重複使用性。
3) 它在編譯時而不是運行時檢查資料類型,保證了類型安全性
4) 它是平台無關的,可移植性
5) 可用於基本資料型別
32 函數模板與類別模板有什麼不同?
答案:函數範本的實例化是由編譯程式在處理函數呼叫時自動完成的,而類別模板的實例化
#必須由程式設計師在程式中明確地指定。
33 .winsock建立連線的主要實作步驟? (非常重要,必問)
##答:伺服器端:socker()建立套接字,綁定(bind)並監聽(listen),用accept()
等待客戶端連線。
客戶端:socker()建立套接字,連線(connect )伺服器,連線上後使用send()#和recv(
##) ,在套接字上寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
伺服器端:accept()發現有客戶端連接,建立一個新的套接字,自身重新開始等待連
接。這個新產生的套接字使用send()#和recv()寫讀數據,直到數據交換完畢,closesock
et()關閉套接字。
34 行程和執行緒的差異。
答案:線程是指進程內的一個執行單元,也是進程內的可調度實體.與進程的區別:(1)調度:執行緒作為調度和分配的基本單位,進程作為擁有資源的基本單位(2)並發性:不僅進程之間可以並發執行,同一個進程的多個執行緒之間也可並發執行(3)擁有資源:進程是擁有資源的一個獨立單位,執行緒不擁有系統資源,但可以存取隸屬於進程的資源.(4)系統開銷:在創建或撤銷進程時,由於系統都要為之分配和回收資源,導致系統的開銷明顯大於建立或撤銷執行緒時的開銷。35. C 是不是型別安全的?
答案:不是。兩個不同類型的指標之間可以強制轉換(用reinterpret cast)#。 C#是型別安全的。
如果用VC開發程序,常見這麼幾個錯誤,C2001,c2005,c2011,這些錯誤的原因是什麼。
37巨集與內聯函數的差異
解析:內嵌函數和巨集都是在程式出現的地方展開,內聯函數不是透過函數呼叫實現的,是在呼叫函數的程式處將它展開(在編譯期間完成的);巨集同樣是;不同的是:內聯函數可以在編譯期間完成諸如類型檢測,語句是否正確等編譯功能;宏就不具有這樣的功能,而且宏展開的時間和內聯函數也是不同的(在運行期間展開)38 win32中訊息循環Windows程式的入口是哪裡?寫出Windows訊息機制的流程
解析:Windows程式的入口是WinMain()函數。 Windows應用程式訊息處理機制:A. 作業系統接收應用程式的視窗訊息,將訊息投遞到該應用程式的訊息佇列中 B. 應用程式在訊息循環中呼叫GetMessage函數從訊息佇列中取出一則的訊息,取出訊息後,應用程式可以對訊息進行一些預處理。 C. 應用程式呼叫DispatchMessage,將訊息回傳給作業系統。 D. 系統利用WNDCLASS結構體的lpfnWndProc成員保存的視窗過程函數的指標呼叫視窗過程,對訊息進行處理。39:談談你對程式設計規範的理解或認知
程式設計規範可總結為:程式的可行性,可讀性、可移植性以及可測試性。說明:這是程式設計規範的總綱目,面試者不一定要去背誦上面給出的那幾個例子,應該去理解這幾個例子說明的問題,想一想,自己如何解決可行性、可讀性、可移植性以及可測試性這幾個問題,結合以上幾個例子和自己平常的程式設計習慣來回答這個問題。
40串流運算元重載為什麼回傳參考
#在程式中,串流運算元>>和< ;fc0d33b7c76a6c7fea76ee2de50f7808」
D. 三目運算子「? :」解析:沒有理由 ABD都不行 #2.在以下有關C 類別的描述中,不正確的是
# A.C 語言引入類別主要起兩個作用,作為資料封裝機制和作為類型定義機制 B.C 類別中定義的資料和函數分別稱為資料成員和成員函數C.C 類別作為資料封裝機制,將資料及作用於資料的操作組織在一起,實現了資訊隱藏
D.C 類別中的成員可分為四種:公有成員、保護成員、私有成員與友元
正確答案:D
#3.設有int x = 123,語句可產生「 123」形式的輸出(「」代表空格)。
A.cout 41ad8964d4b7b5f06e7a357fab31a50f class Sample {…};
B.template1bbcbf404aff658cf5eed197e6af2bc7 class Sample {…} ; C.template8c49dd555a9806de561d35e83b4ae27d class Sample {…}; D.template17441c4bf03cd3139b4c9059754f3614 Sample {…};#正確答案: C5#非C 內建類型A 和B,在哪幾種情況下B能隱式轉換為A? [C 中] a. class B : public A { ……}
b. class B { operator A( ); }
c. class A { A ( const B& ); }
第四項: 賦值操作,雖不是正宗的隱式類型轉換,但也可以勉強算一個
6
11大就就就就指向該物件
成員函數擁有this指針
9.假定AB为一个类,则执行“AB a(4),b[3],*p[2];”语句时,自动调用该类构造函数的次数为:B
A) 3 B) 4 C) 6 D) 9
10.假定要对类AB定义加号操作符重载成员函数,实现两个AB类对象的加法,并返回相加结果,则该成员函数的声明语句为:B
A) AB operator+(AB &a,AB &b)
B) AB operator+(AB &a)
C) operator+(AB a)
D) AB & operator+()
11.有二维字符数组char s[4][6]={"zhang","gao","tang","wang"};执行程序coutdaeeae8786145a0c6601e10ab13634c6打印结果是多少
using namespace std; class A1{ public: int a; static int b; A1(); ~A1(); }; int main() { cout << sizeof(A1) <<endl; }
解析:是4, 静态变量是存放在全局数据区的, 而sizeof是计算局部栈中分配的大小。
13.死锁的处理
解析:鸵鸟策略、预防策略、避免策略、检测与解除死锁,只要知道概念就行,不需要掌握
14. 非C++内建型别 A 和 B,在哪几种情况下B能隐式转化为A?[C++中等]
解析:a. class B : public A { ……} // B公有继承自A,可以是间接继承的
b. class B { operator A( ); } // B实现了隐式转化为A的转化
c. class A { A( const B& ); } // A实现non-explicit的参数为B(可有其他带默认值的参数)构造函数
d. A& operator= ( const A& ); // 赋值操作,虽不是正宗的隐式类型转换,但也可以勉强算一个
15以下代码有什么问题?[STL易]
typedef vector IntArray;
IntArray array;
array.push_back( 1 );
array.push_back( 2 );
array.push_back( 2 );
array.push_back( 3 );
// 删除array数组中所有的2
for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
{
if( 2 == *itor ) array.erase( itor );
}
解析:其实里面隐藏着一个很严重的错误:当veci.erase(iter)之后,iter就变成了一个野指针,对一个野指针进行 iter++ 是肯定会出错的。
16 下列代码的输出值是多少?
class A{};
class A1{};
class B : public A{};
class C : public A, public A1{};
class D : public virtual A{};
cout << sizeof ( A ) << endl;
cout << sizeof ( B ) << endl;
cout << sizeof ( C ) << endl;
cout << sizeof ( D ) << endl;
解析:答案:1 , 1, 1,4說明:空類別所佔的空間為1,單一繼承的空類別空間也為1,多重繼承的空類別空間還是1, 但是虛繼承涉及虛表(虛指針),所以大小為4。
相關文章:
以上是C++精選面試題,一定要了解的詳細內容。更多資訊請關注PHP中文網其他相關文章!