面試 C++ 程序員,什麼樣的問題是好問題?


對於應屆生:

  • 標準庫各容器的基本操作的複雜度。標準庫演算法的複雜度,例如 std::sort() 的平均複雜度、最壞複雜度(答 O(N^2) 和 O(N log N) 都算對),最壞情況什麼時候出現。
  • 標準庫各容器(deque 除外)的數據結構(標準黨勿噴,主流 STL 實現的數據結構都差不多),以及 vector 的容量增長方式。如果回答得特別好,還可以補充問為什麼 vector::push_back() 的複雜度是分攤之後的 O(1),作為加分。
  • 出一道使用 lower_bound / upper_bound 能輕鬆解決的簡單演算法題;或者實現 set_intersection() 或 set_union() 或 merge();或者實現 word count,統計每個單詞出現的次數(最多十幾行代碼),如果有時間,輸出時再按出現次數排序。

對於社招,補充問:

  • 迭代器失效。(不要求記住所有的場景,但要有這個概念,其實知道數據結構的話不難推理。)
  • 標準庫的線程安全性。
  • 自動化對象生命期管理,智能指針,循環引用,weak_ptr。
  • list 的 insert()/erase() 與 vector 相比哪個快。(這個不是那麼簡單。)

關於什麼是好的面試題,多說幾句我的看法:

  • 面試官向誰負責。通常應聘者會面試幾輪,收集多個面試官的 feedback,交給 hire manager 或 hire committee 決定是否錄用。也就是說面試官無權單獨決定是否錄用這個候選人。在此前提下,面試官的任務是收集足夠多的有效信息(包括面試題、答案、答題過程等等),供 hire manager 或 hire committee 決斷。因此,面試題要有說服力。應聘者答上了這道面試題,能說明什麼,如果沒答上來,又能說明什麼。不符合這一要求的不是好題目。
  • 難度與區分度。難度定位在「一個合格的 C++ 程序員應該掌握的基本知識」,是招能用 C++ 幹活的人,不是招標準控或語言律師。所有人都能做出來和所有人都做不出來的題目,沒有區分度,不是好題目。所有應聘者都能通過或者所有應聘者都被刷掉的面試官也不是好面試官。
  • 公平性與可重複性。技術面試題應該有比較公認的正確答案,怎麼樣算答得好,不僅由面試官一個人做出判斷,hire manager 和 hire committee 也能重複這一判斷。一套好題目,能起到篩選多個面試者的作用,比如「眼前這個應聘者的回答與過去六個月里的應聘者相比,處於前 10 % 的位置」,這就是不錯的客觀標杆。

不敢妄言什麼是「好問題」,僅僅只是說說我喜歡問什麼樣的問題。

我在面試的時候主要考查面試者分析問題和解決問題的能力,因此我會給出一個實際工作中會遇到的問題,讓面試者分析問題,給出解決方案,最後用具體的代碼實現這個方案。解決這個問題需要的知識點都非常非常基本,絕對不會超過《數據結構與演算法》這門課能夠覆蓋的內容。換句話說,也就是計算機相關專業的第二學期專業課就能夠涉及到的內容,僅此而已,並非很多人宣稱的必須精通 ACM,精通《演算法導論》那麼恐怖。

在面試過程中,最重要的就是分析問題和解決問題。一個應聘者如果僅僅滿足於背課本做習題的話,遇到實際工作中的問題往往不知道如何把課本上的知識用上去,因此光死讀書,平時不實踐是不行的。至於花時間去閱讀什麼「面試寶典」、「腦筋急轉彎」什麼的,就更是沒有意義了。很多網上廣為流傳的「判斷單鏈表是否有環」啊,「不開闢額外空間把數組前 n 個元素移動到尾部」啊之類的題目,本質上和腦筋急轉彎並沒有區別,這種題目並不能考查出面試者分析問題和解決問題的能力,在實際面試中也是不會用的。

總之,只要基礎知識掌握足夠牢靠,再加上平時足夠的實踐,通過面試就完全沒問題了。事實上,我遇到過有一個應聘者 fopen 不會用,memcpy 的調用方法也記錯了,但這些都不是問題,由於他分析問題思路完全正確,寫代碼的時候格式規範,條理清晰,因此最後也毫無懸念地通過了面試。

至於模板、容器、虛表、多繼承等 C++ 語言細節,正常情況下我是不會在面試里考查的,除非一個應聘者表現極其好,為了讓他能夠再得到一些額外的加分,我會故意問一些瑣碎的語言細節,好讓他有機會表現一下。如果他答上來了,我就在評語里再表揚他幾句;如果沒答上來,那就算了,無妨。


我認為有一個好問題適合面試所有的程序員,那就是拿出一份三千行以上的代碼,給他半小時的閱讀時間,然後提出這些問題:
1,這份代碼是不是商用代碼/適不適合商用
2,這份代碼的缺陷是哪些
3,這份代碼有哪些不規範的地方
4,指出代碼的分層


轉帖一下我在其他問題里的答案

------------------------
實際的面試中,一般按照以下的標準來區分水平。(隨便寫的,不成系統)
1 聽說過C++
常見的問題 什麼是類,什麼繼承
new和malloc有什麼區別
什麼是虛函數,什麼是虛繼承
之類的泛泛而談的入門問題
2 會C++
new實際上執行了什麼操作,可能在什麼步驟出現異常
怎麼寫一個class,禁止分配在棧上
怎麼突破private的限制訪問變數
虛繼承的細節
怎麼自己模擬實現引用
3 比較了解C++
主要是一些邊角的語法或者是不常見的問題
逗號表達式,位域
初始化列表的異常怎麼捕獲
對於常見的主流編譯器,寫不寫inline有什麼影響
完美轉發
怎麼在編譯器判斷一個類中有沒有定義某個特定的方法
構造函數中調析構函數會有什麼結果


作為一個面試者,能力有限,只能說別問那些網上一抓一大把的死問題
如:實現一個string類,實現一個鏈表,socket套接字,類似GetMerory函數的改錯題…
每次看到這些我就想吐了,這些問題作為應屆生題目還好…我面試的都是兩年以上工作經驗的…不知道是他們懶還是能力有限
上次有一家公司就出的不錯,讓你現場用vs2008實現一個一個功能,可以上網查資料…誰都有遇到問題的時候,關建是看你解決問題的能力


我做面試官也有一段時間了,遇到過形形色色的C++程序員,水平參差不齊。這裡說一下我的經驗吧:

我最常問的問題是,用C++寫一個有理數類,class Rational,實現基本的加減乘除和輸入輸出操作。
別看這麼小小的一個問題,居然可以考察到非常之多的地方,猶如闖關遊戲一般,直到把這個面試者推向極限。

  1. 完全不知所云的,甚至有說忘了有理數是啥的,我就耐心地告訴他,兩個整數之比定義為有理數,第一個叫做分子,第二個叫做分母。然後禮貌地結束面試。
  2. 如果搞不清楚的怎麼做的,我會給一個main函數的示例(見下面的代碼),告訴他「面向介面編程,不要面向實現編程」。我發現有經驗的人,會問我介面或者對象的行為是什麼樣的。
  3. 能搞清楚問題,首先讓他寫出類的聲明,然後就可以問,哪些是public,哪些是private的,什麼是運算符重載。為何傳遞參數要寫 const Rational。
  4. 繼續問,構造函數,析構函數,拷貝構造函數,operator= 是怎麼回事,相關知識云云,構造函數是不是前面要加 explicit 修飾。
  5. 繼續問 istream和ostream的重載怎麼寫,friend 函數是怎麼回事。
  6. 讓面試者寫代碼,儘可能完整地實現這個類的成員函數,中間觀察編程習慣,代碼風格等等
  7. 有理數分母不能為0,看看面試者是不是夠仔細,還有對C++的異常控制是否有了解。包括數字過大的時候,整數溢出了是否有考慮。
  8. 1/3+1/3+1/3輸出應該是1,所以分子分母要約分,求最大公約數這個點想到。如果有負數,最大公約數怎麼求?
  9. istream輸入的情況可能會很多,涉及到字元串的解析,"3.5","1/3", "-1/5", "-0.3",看看面試者能正確處理多少種情況?順便問一下測試方面的問題。
  10. 有理數的分子分母可能會很大,是不是可以考慮模板化,寫成Rational&,然後可以有個Bigint的類來實現 typedef Rational& HighPrecisionRational;

//我期望看到的解答
#include &

class Rational{
public:
Rational();
Rational(int x);
Rational(int x, int y);
Rational(const Rational r);
const Rational operator=(int x);
const Rational operator=(const Rational r);
virtual ~Rational();

bool operator== (const Rational other) const;

friend const Rational operator+ (const Rational r1,
const Rational r2);
friend const Rational operator- (const Rational r1,
const Rational r2);
friend const Rational operator* (const Rational r1,
const Rational r2);
friend const Rational operator/ (const Rational r1,
const Rational r2);
friend std::ostream operator&<&< (std::ostream, const Rational r); friend std::istream operator&>&> (std::istream, Rational r);
private:
static int gcd(int p, int q);
int num; //numerator
int div; //divisor
};

int main(int argc, char* argv[])
{
Rational a(1, 3); //a等於三分之一
Rational b = 3; //b等於3,3也是有理數
b = a;
Rational c(a+b+Rational(1,3)); //有理數可以做加法
std::cout &<&< "a=" &<&< a &<&< std::endl; std::cout &<&< "b=" &<&< b &<&< std::endl; std::cout &<&< "c=" &<&< c &<&< std::endl; //輸出結果 std::cout &<&< "Please input a Rational number like 13/15" &<&< std::endl; Rational d; std::cin &>&> d;
std::cout &<&< "value d+1=" &<&< d+1 &<&< std::endl; return 0; } //gcc -g -O0 -o rational Rational.cpp -lstdc++

面試者能闖到最後一關的,我已經比較滿意了。整個面試的過程中圍繞著一個功能的實現反覆交流和改進,我們的談話已經涉及到了C++、字元串、演算法、數學、代碼風格、軟體工程、測試的很多方面的知識了;同時對面試者的表達能力,溝通能力,性格方面也有所了解了。

finally. 我會給一個殺手級問題,這裡分子分母約分用到了gcd,請問時間複雜度是多少?啊哈,這裡要請出Knuth爺爺的《計算機程序設計藝術》啦!wow!

========================華麗的分割線========================
非常感謝 @時習之 的建議。我補充說明一下
1. 確實如他所說的,先給出operator+=,然後再去實現非友元的operator+,這樣是能減少代碼冗餘的;如果只是要求實現加減乘除操作,用友元operator也沒有問題。
2. 如果只是考慮在控制台輸入輸出,iostream就能滿足需求了; 如果更往深了討論,比如涉及到字元串解析(sstream),文件的讀寫(fstream),這個時候就需要重載參數為basic_stream

Template&
basic_stream& operator&<&< (basic_stream& os, const Rational r);

Template&
basic_stream& operator&>&> (basic_stream& os, const Rational r);

3. std::complex是複數,而Rational是有理數,實現細節上還是多有不同的。如果是要求面試者實現一個complex的話,我曾要求他實現出複數的乘方和開方運算。
4. operator= 應該返回 const Rational,已改正;
5. 為何不直接用系統默認合成的構造析構函數。Rational x; 的值是多少呢?我的習慣是初始化為0,而且不希望分母為0
6. 構造函數Rational::Rational(int x),我認為是不應該聲明為explicit的,因為我希望重載了operator+運算符之後,r+1, 1+r都能work。

我們這裡並不是要求應聘者是一名C++語法專家,更多的是希望在相互討論的過程中,觀察面試者思考問題的深度和全面性,以及應變能力。


我一般會循序漸進的問問題,以C++的虛函數為例。

  1. 了解多態么?它是怎麼實現的?什麼時候應該使用它?
  2. 在語言層面,虛函數是怎樣實現的?為什麼還要區分虛函數和普通函數,都成虛函數不好么?
  3. 虛表裡存儲的是什麼?
  4. 如果基類定義先聲明了f函數後聲明了g函數,子類定義會反過來(真正面試的時候會有樣例代碼給出),那麼虛表裡第一項是什麼?
  5. 如果有多繼承,虛表內會怎樣?
  6. 等等。。。

這只是個大體思路,關鍵是看求職者的現場反應能力和鏈接能力,比如:

  • 第一題,如果提到靜態多態,並且簡單詢問後確認懂得什麼是靜態多態則有額外加分。
  • 第二題,提到和其他語言的對比(如java oc python 等),有額外加分。
  • 第四題,關鍵不在於答案,而在於回答的思路。如果在回答出大體原理之後加以說明這東西是undefined,不應該依賴於這個結果,有額外加分。
  • 第五題,如果一開始求職者不太了解這個事情,但是通過我簡單的提示,能夠沿著這個思路走下去,無論對錯,均有額外加分。

如果在面試中會詢問到了求職者之前沒有思考過的問題,我會給出適當的提示,逼迫其現場思考。

如果中間被求職者帶跑了,比如問第一題的時候扯到模板元編程了,我的態度就是隨著他跑,在他自己最擅長的領域才能看出他的思路究竟是怎樣的。

總之,盡量通過方方面面探知求職人員對技術核心思想的把握能力,如果在面試之前他就考慮的很透徹,這是上上之選(原因是其會自己沿著正確的方向獨立思考),如果在面試中可以現場考慮出大概,這是上之選(原因是其邏輯思維還不錯)。

思維方式很重要,某種程度上,這東西決定一個人的命運。


學習C++:實踐者的方法
看完這個樓主或許會知道應該提問那些重點


我推薦一個吧,相比C++語法和標準庫,我個人更加喜歡這個問題,這也是當時經理面試我的唯一問題:"談一談在你眼中的C++哲學和思想」,這個問題我覺得可以看出他對C++的喜愛程度、研究程序,這遠遠比那些利用手冊可以查到的語法更加重要。只有去探討了C++的哲學與思想,他才知道C++到底為什麼是這樣,才會去更加明白何時、何地、如何地利用C++,當然也更加能確定他是否喜愛上了C++(甚至抱有著一種信仰),只有愛上了一個東西,他才會更加對他寫的C++代碼負責,也許這有點兒所謂的宗教色彩,但是有時候只有這種宗教般的信仰,才能讓他更加的執著。這樣的C++程序員,我想遠比記憶了語法的C++程序員更加難得與彌足珍貴。


幾個思路吧
1. 入門問題,基本的數學素養和邏輯分析,C++語言的語法、重要的數據結構和演算法思路,鑒別面試者的基本功。
2. C++11的新特性,以及對這些特性的看法?或者,你看的C++的著作,看看是否是一個學習型的程序員。
3.進階一點的話題,例如容器、模版、面向對象、SEH等,看面試者的知識面和功底。
4.實戰,你以前碰到的最莫名其妙的bug,以及如何解決的?看面試者的綜合經驗和能力


靜態局部變數存放在哪裡?它的地址在什麼編譯時還是運行時確定的?


如果是老鳥,我會問:如果有一個準備學習C++的學生讓你推薦書籍,你會給出哪些書單?
如果是菜鳥,我會選擇一些操作系統、數據結構的知識,再搭載一些STL分析。


有女朋友嗎?


去http://tilaile.com刷題吧,一堆一堆的,都有答案…


最新的幾個標準的大致內容,及其個人點評


去nowcoder上看吧,C++題目一把一把的


問一些C++比較隱蔽的問題。

如果他知道答案,會接著問原理。

如果不知道答案,這樣更好,我就會問如果你是設計者,你會如何解決問題,如果他能自圓其說,說明邏輯思維很好。


你還準備在這個坑中呆多久?


其實應該按c++的方向去面試.

因為c++涉及面實在是太廣了.

大體方向

1.網路

2.圖像處理

3.遊戲引擎

4.客戶端

5.音視頻

6.逆向與系統安全

7.界面組件管理

8.瀏覽器引擎

9.編譯器與解釋器

10.數學庫

11.加解密

12.資料庫

不同領域的c/c++思考和解決問題的方式不太一樣 不能一概而論.

很多c++程序員沉迷於自己華麗的語法糖 模板和對象模型, 卻忘記了做寫代碼的目的是解決實際問題.


有人說考基礎 那麼我問問你. 現在讓你默寫漢語拼音聲母和韻母表 你確定可以完整的寫出來么?


問啥內容?我們都是讓應聘者來面試之前做一份猿圈的題,然後根據結果報告有針對的問,沒什麼固定的,畢竟每個人的專業水準和擅長都不一樣。


推薦閱讀:

發現很多外掛和木馬編寫都是用MFC,MFC有必要學嗎?
如何看待阿里2016校招研發工程師筆試題題目?
用一年時間如何能掌握 C++ ?
如何通過自學找到一份開發的工作?
有哪些看似簡單其實非常精妙的代碼?

TAG:面試 | 程序員 | 程序員面試 | C |