程序員面試——C++工程師面試大全第一部分

1.static 關鍵字的作用

1. 全局靜態變量

在全局變量前加上關鍵字 static,全局變量就定義成一個全局靜態變量.

靜態存儲區,在整個程序運行期間一直存在.

初始化:未經初始化的全局靜態變量會被自動初始化爲 0(自動對象的值是任意的,除非他 被顯式初始化);

作用域:全局靜態變量在聲明他的文件之外是不可見的,準確地說是從定義之處開始,到文件結尾.

2. 局部靜態變量

在局部變量之前加上關鍵字 static,局部變量就成爲一個局部靜態變量.

內存中的位置:靜態存儲區

初始化:未經初始化的全局靜態變量會被自動初始化爲 0(自動對象的值是任意的,除非他被顯式初始化);

作用域:作用域仍爲局部作用域,當定義它的函數或者語句塊結束的時候,作用域結束.但 是當局部靜態變量離開作用域後,並沒有銷燬,而是仍然駐留在內存當中,只不過我們不能再對 它進行訪問,直到該函數再次被調用,並且值不變;

3. 靜態函數

在函數返回類型前加 static,函數就定義爲靜態函數.函數的定義和聲明在默認情況下都 是 extern 的,但靜態函數只是在聲明他的文件當中可見,不能被其他文件所用.

函數的實現使用 static 修飾,那麼這個函數只可在本 cpp 內使用,不會同其他 cpp 中的同 名函數引起衝突;

warning:不要再頭文件中聲明 static 的全局函數,不要在 cpp 內聲明非 static 的全局函 數,如果你要在多個 cpp 中複用該函數,就把它的聲明提到頭文件裏去,否則 cpp 內部聲明需加 上 static 修飾;

4.類的靜態成員

在類中,靜態成員可以實現多個對象之間的數據共享,並且使用靜態數據成員還不會破壞隱 藏的原則,即保證了安全性.因此,靜態成員是類的所有對象中共享的成員,而不是某個對象的 成員.對多個對象來說,靜態數據成員只存儲一處,供所有對象共用

5. 類的靜態函數

靜態成員函數和靜態數據成員一樣,它們都屬於類的靜態成員,它們都不是對象成員.因此, 對靜態成員的引用不需要用對象名.

在靜態成員函數的實現中不能直接引用類中說明的非靜態成員,可以引用類中說明的靜態成 員(這點非常重要).如果靜態成員函數中要引用非靜態成員時,可通過對象來引用.從中可看 出,調用靜態成員函數使用如下格式:<類名>::<靜態成員函數名>(<參數表>);

 

2.C++和 C 的區別

設計思想上:

C++是面向對象的語言,而 C 是面向過程的結構化編程語言

語法上:

C++具有重載,繼承和多態三種特性

C++相比 C,增加多許多類型安全的功能,比如強制類型轉換,

C++支持範式編程,比如模板類,函數模板等

 

3.C++中四種 cast 轉換

C++中四種類型轉換是:static_cast, dynamic_cast, const_cast, reinterpret_cast

1,const_cast 用於將 const 變量轉爲非 const

2,static_cast 用於各種隱式轉換,比如非 const 轉 const,void*轉指針等, static_cast 能用於多態向上 轉化,如果向下轉能成功但是不安全,結果未知;

3,dynamic_cast 用於動態類型轉換.只能用於含有虛函數的類,用於類層次間的向上和向下轉化.只能轉指 針或引用.向下轉化時,如果是非法的對於指針返回 NULL,對於引用拋異常.要深入瞭解內部 轉換的原理. 向上轉換:指的是子類向基類的轉換 向下轉換:指的是基類向子類的轉換 它通過判斷在執行到該語句的時候變量的運行時類型和要轉換的類型是否相同來判斷是否 能夠進行向下轉換.

4,reinterpret_cast 幾乎什麼都可以轉,比如將 int 轉指針,可能會出問題,儘量少用;

5,爲什麼不使用 C 的強制轉換? C 的強制轉換表面上看起來功能強大什麼都能轉,但是轉化不夠明確,不能進行錯誤檢查, 容易出錯.

 

4.C/C++ 中指針和引用的區別

1.指針有自己的一塊空間,而引用只是一個別名;

2.使用 sizeof 看一個指針的大小是 4,而引用則是被引用對象的大小;

3.指針可以被初始化爲 NULL,而引用必須被初始化且必須是一個已有對象 的引用;

4.作爲參數傳遞時,指針需要被解引用纔可以對對象進行操作,而直接對引 用的修改都會 改變引用所指向的對象;

5.可以有 const 指針,但是沒有 const 引用;

6.指針在使用中可以指向其它對象,但是引用只能是一個對象的引用,不能 被改變;

7.指針可以有多級指針(**p),而引用至於一級;

8.指針和引用使用++運算符的意義不一樣;

9.如果返回動態內存分配的對象或者內存,必須使用指針,引用可能引起內存泄露.

 

5.你說一下你理解的 c++中的 smart pointer 四個智能指針: shared_ptr,unique_ptr,weak_ptr,auto_ptr

C++裏面的四個智能指針: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中後三個是 c++11 支持,並且第一個已經被 11 棄用.

爲什麼要使用智能指針: 智能指針的作用是管理一個指針,因爲存在以下這種情況:申請的空間在函數結束時忘記釋放,造成內存泄漏.使用智能指針可以很大程度上的避免這個問題,因爲智能指針就是一個類, 當超出了類的作用域是,類會自動調用析構函數,析構函數會自動釋放資源.所以智能指針的作 用原理就是在函數結束時自動釋放內存空間,不需要手動釋放內存空間.

1. auto_ptr(c++98 的方案,cpp11 已經拋棄) 採用所有權模式.

auto_ptr< string> p1 (new string ("I reigned lonely as a cloud.”));

auto_ptr<string> p2;

p2 = p1; //auto_ptr 不會報錯.

此時不會報錯,p2 剝奪了 p1 的所有權,但是當程序運行時訪問 p1 將會報錯.所以 auto_ptr 的缺點是:存在潛在的內存崩潰問題!

2. unique_ptr(替換 auto_ptr)

unique_ptr 實現獨佔式擁有或嚴格擁有概念,保證同一時間內只有一個智能指針可以指向該對象.它對於避免資源泄露(例如“以 new 創建對象後因爲發生異常而忘記調用 delete”)特 別有用.

採用所有權模式,還是上面那個例子

unique_ptr<string> p3 (new string ("auto")); //#4

unique_ptr<string> p4; //#5

p4 =p3;//此時會報錯!!

編譯器認爲 p4=p3 非法,避免了 p3 不再指向有效數據的問題.因此,unique_ptr 比 auto_ptr 更安全.

另外 unique_ptr 還有更聰明的地方:當程序試圖將一個 unique_ptr 賦值給另一個時,如 果源 unique_ptr 是個臨時右值,編譯器允許這麼做;如果源 unique_ptr 將存在一段時間,編譯器將禁止這麼做,比如:

unique_ptr<string>pu1(“hello world”);

unique_ptr<string>pu2;

pu2=pu1; //#1not allowed

unique_ptr<string>pu3;

pu3=unique_ptr<string>(“you”); //#2 allowed

其中#1 留下懸掛的 unique_ptr(pu1),這可能導致危害.而#2 不會留下懸掛的 unique_ptr, 因爲它調用 unique_ptr 的構造函數,該構造函數創建的臨時對象在其所有權讓給 pu3 後就會 被銷燬.這種隨情況而已的行爲表明,unique_ptr 優於允許兩種賦值的 auto_ptr .

注:如果確實想執行類似與#1 的操作,要安全的重用這種指針,可給它賦新值.C++有一個 標準庫函數 std::move(),讓你能夠將一個 unique_ptr 賦給另一個.例如:

unique_ptr<string>ps1,ps2;

ps1=demo(“hello”);

ps2=move(ps1);

ps1=demo(“Alexia”);

cout<<*ps2<<*ps1<<endl;

3. shared_ptr

shared_ptr實現共享式擁有概念.多個智能指針可以指向相同對象,該對象和其相關資源 會在“最後一個引用被銷燬”時候釋放.從名字 share 就可以看出了資源可以被多個指針共享, 它使用計數機制來表明資源被幾個指針共享.可以通過成員函數 use_count()來查看資源的所有 者個數.除了可以通過 new 來構造,還可以通過傳入 auto_ptr, unique_ptr,weak_ptr 來構造. 當我們調用 release()時,當前指針會釋放資源所有權,計數減一.當計數等於 0 時,資源會被釋放.

shared_ptr 是爲了解決 auto_ptr 在對象所有權上的侷限性(auto_ptr 是獨佔的), 在使 用引用計數的機制上提供了可以共享所有權的智能指針.

成員函數: use_count 返回引用計數的個數 unique 返回是否是獨佔所有權( use_count 爲 1) swap 交換兩個 shared_ptr 對象(即交換所擁有的對象) reset 放棄內部對象的所有權或擁有對象的變更, 會引起原有對象的引用計數的減少 get 返回內部對象(指針), 由於已經重載了()方法, 因此和直接使用對象是一樣的.如 shared_ptr<int> sp(new int(1)); sp 與 sp.get()是等價的

4.weak_ptr

weak_ptr 是一種不控制對象生命週期的智能指針, 它指向一個 shared_ptr 管理的對象. 進行該對象的內存管理的是那個強引用的 shared_ptr. weak_ptr 只是提供了對管理對象的一個 訪問手段.weak_ptr 設計的目的是爲配合 shared_ptr 而引入的一種智能指針來協助 shared_ptr 工作, 它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構造, 它的構造和析 構不會引起引用記數的增加或減少.weak_ptr 是用來解決 shared_ptr 相互引用時的死鎖問題, 如果說兩個 shared_ptr 相互引用,那麼這兩個指針的引用計數永遠不可能下降爲 0,資源永遠不 會釋放.它是對對象的一種弱引用,不會增加對象的引用計數,和 shared_ptr 之間可以相互轉化,shared_ptr 可以直接賦值給它,它可以通過調用lock函數來獲得 shared_ptr.

 

6.野指針是什麼?

野指針就是指向一個已刪除的對象或者未申請訪問受限內存區域的指針

 

7.介紹一下 C++中的智能指針

智能指針主要用於管理在堆上分配的內存,它將普通的指針封裝爲一個棧對象.當棧對象的 生存週期結束後,會在析構函數中釋放掉申請的內存,從而防止內存泄漏.C++ 11 中最常用的 智能指針類型爲 shared_ptr,它採用引用計數的方法,記錄當前內存資源被多少個智能指針引用. 該引用計數的內存在堆上分配.當新增一個時引用計數加 1,當過期時引用計數減一.只有引用 計數爲 0 時,智能指針纔會自動釋放引用的內存資源.對 shared_ptr 進行初始化時不能將一個普通指針直接賦值給智能指針,因爲一個是指針,一個是類.可以通過 make_shared 函數或者通 過構造函數傳入普通指針.並可以通過 get 函數獲得普通指針.

 

8.爲什麼析構函數必須是虛函數?爲什麼 C++默認的析構函數不是虛函數

將可能會被繼承的父類的析構函數設置爲虛函數,可以保證當我們 new 一個子類,然後使用 基類指針指向該子類對象,釋放基類指針時可以釋放掉子類的空間,防止內存泄漏.

C++默認的析構函數不是虛函數是因爲虛函數需要額外的虛函數表和虛表指針,佔用額外的內存.而對於不會被繼承的類來說,其析構函數如果是虛函數,就會浪費內存.因此 C++默認的 析構函數不是虛函數,而是隻有當需要當作父類時,設置爲虛函數.

 

9.說一下函數指針

1,定義

函數指針是指向函數的指針變量. 函數指針本身首先是一個指針變量,該指針變量指向一個具體的函數.這正如用指針變量可 指向整型變量,字符型,數組一樣,這裏是指向函數. C 在編譯時,每一個函數都有一個入口地址,該入口地址就是函數指針所指向的地址.有了 指向函數的指針變量後,可用該指針變量調用函數,就如同用指針變量可引用其他類型變量一樣, 在這些概念上是大體一致的.

2,用途:

調用函數和做函數的參數,比如回調函數.

3,示例:

char * fun(char * p) {…} // 函數 fun

char * (*pf)(char * p); // 函數指針 pf

pf = fun; // 函數指針 pf= fun

pf(p); // 通過函數指針 pf 調用函數 fun

 

10.說一下 fork 函數

Fork:創建一個和當前進程映像一樣的進程可以通過 fork( )系統調用:

#include <sys/types.h>

#include <unistd.h>

pid_t fork(void);

成功調用 fork( )會創建一個新的進程,它幾乎與調用 fork( )的進程一模一樣,這兩個進 程都會繼續運行.在子進程中,成功的 fork( )調用會返回 0.在父進程中 fork( )返回子進程 的 pid.如果出現錯誤,fork( )返回一個負值.

最常見的 fork( )用法是創建一個新的進程,然後使用 exec( )載入二進制映像,替換當前進程的映像.這種情況下,派生(fork)了新的進程,而這個子進程會執行一個新的二進制可執 行文件的映像.這種“派生加執行”的方式是很常見的.

在早期的 Unix 系統中,創建進程比較原始.當調用 fork 時,內核會把所有的內部數據結構 複製一份,複製進程的頁表項,然後把父進程的地址空間中的內容逐頁的複製到子進程的地址空 間中.但從內核角度來說,逐頁的複製方式是十分耗時的.現代的 Unix 系統採取了更多的優化, 例如 Linux,採用了寫時複製的方法,而不是對父進程空間進程整體複製.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章