原文題目:The Best Questions for Would-be C++ Programmers: Part 1
鏈接:Topcoder 論壇
原作者 zmij
翻譯過程訂正了原文一些筆誤
引言
在招聘過程中,一個不可缺少而且十分重要的環節是“測試”。“測試”可以為面試官和候選人雙方提供信息。面試官可以由此得知候選人的專業能力以及對編程語言的理解;候選人可以得知該工作所需的技術,以及公司期望的技術水平,甚至可以據此決定是否仍想要該職位。
我曾參加過相當數量的面試,或多或少地成功。對那些不得不面對的問題,我願意分享我的經驗。我還向三位高分的topcoder 成員詢問反饋。他們是bemerry, kyky 以及sql_lall。他們都十分友善地幫我更正不准確的地方並且貢獻了其他的問題。當然,問題的答案可能不是唯一的,不過我盡量把握面試的動態,並讓大家仔細思考這些問題。所以,大家拿起鉛筆,“一起鑒定潛在的C++程序員以及有潛力的C++程序員”。
1. 什么是類?
類是一種封裝數據的方式。該方式在定義抽象數據類型的同時,定義了初始化的條件以及允許的操作。
2.C struct 與 C++ struct的區別?
- C struct 只是將數據組合起來,它只是有特性(數據)而沒有包括行為。(函數可以使用結構體但並不是與結構體綁定的)
- Typedef 的別名在C語言中沒有自動地為結構體生成,比如:
// a C struct struct my_struct { int someInt; char* someString; }; // 你聲明了一個my_struct類型的結構體 struct my_struct someStructure; // 在C語言,你不得不使用typedef來方便地聲明變量 typedef my_struct MyStruct; MyStruct someOtherStuct; // a C++ struct struct MyCppStruct { int someInt; char* someString; }; // 聲明了 MyCppStruct類型的一個變量 MyCppStruct someCppStruct;
// 由此可以看到該名字被自動typedef
- 最重要的是,C struct並沒有提供面向對象概念的實現,比如封裝和多態。而且,“C struct不能擁有靜態(static)的成員或成員函數”。C++ struct 實際上是class,區別只是在於默認的成員以及基類訪問標識符:class默認為private,而struct是public.
3.const關鍵字的含義,相比#define的優勢?
- 簡而言之,const意味着只讀。一個const聲明的,有名字的常量,就像是一個普通的變量,除了它的值不能被修改。任何的數據類型,無論是用戶定義或者內置,都可以定義為為const,比如:
-
// myInt變量是一個只讀的整形 const int myInt = 26; // 與上一行一樣,此處是說明const既可以左結合也可以右結合 int const myInt = 26; // 一個指向常量的指針,不能通過指針修改對象的值,但並不意味所指的是常量 const MyClass* myObject = new MyClass(); // 一個指針常量, 不能指向別的對象,指向的對象本身可以修改 MyClass* const myObject = new MyClass(); // myInt 是一個指向常量的指針常量 const int someInt = 26; const int* const myInt = &someInt;
- #define 容易出錯,因為它不像const一樣由編譯器強制執行。它只是由預處理器進行的替換,並不會有任何的檢查。這意味着const關鍵字會保證類型的正確,而#define不行。使用define而產生的bug會比較難發現,因為它們沒有被放在符號表。
- 在C++中,一個常量會有一個作用域,就像一個普通的變量。相反,#define定義的名字是全局有效的,因此可能產生沖突。一個常量必須在聲明時定義,即在聲明時賦值,而define可以為空。
- 使用const的代碼會自然地受到編譯器的保護,避免疏忽。比如,對於一個類的狀態而言,const成員變量不能被修改,const成員函數不能修改類的成員;對於函數參數而言,const參數的值不能在函數內被修改。最后,編譯器的優化對有名字的常量依然有效。
- 總而言之,使用const會比#define有更少的bug和麻煩。
4.解釋private, public, 和protected訪問控制符?
- public:成員變量和方法可以從類外直接訪問。
- private:成員變量和方法不能被類外直接訪問。
- protected:成員變量和方法不能直接從類外訪問,但子類可以。
- 這些控制符在繼承關系中同樣被使用,但含義不同,見下一個問題。
5.解釋public以及private繼承?
- C++中,public繼承是最常用的繼承機制,通過在基類名字前加上public關鍵字使用。例子如下:
-
class B : public A { };
- private繼承是C++默認的繼承方法,如果不聲明控制符,將會是私有繼承:
-
class B : private A { }; // or class B : A { };
- 在繼承語法中,public關鍵字意味着從基類繼承的 公有/私有/保護/ 的成員變量在繼承類中依然保持原有的訪問控制符。 private關鍵字意味着所有的基類成員,無論原有的訪問控制符是什么,在繼承類中都改為私有。
- 使用公有繼承,以下的類型轉換是允許的。在A等於B的情況,該轉換是安全的,但如果B有新的方法,那就是另外的話題了:
-
// B 就是 A
class B : public A {};
A* aPointer = new B();但是,如果使用私有繼承,基類的成員在子類當中是私有的,無法被訪問:
-
class A { public: A(); ~A(); void doSomething(); }; void A :: doSomething() { } class B : private A { public: B(); ~B(); }; B* beePointer = new B(); // 錯誤!編譯器報錯:該方法不可訪問 beePointer->doSomething();
// 錯誤!編譯器報錯:存在B* 到 A*的類型轉換,但是不可訪問 A* aPointer = new B();
// 對於以下情形,標准認為是未定義的行為
// 編譯器至少對第一個清晰報錯:B並不是多態類型
A* aPointer2 = dynamic_cast<A*>(beePointer); A* aPointer3 = reinterpret_cast<A*>(beePointer);
(未完待續)