二十万字C/C++、嵌入式软开面试题全集宝典七
目錄
121、 怎樣判斷兩個浮點數(shù)是否相等?
122、 宏定義一個取兩個數(shù)中較大值的功能
123、 define、const、typedef、inline使用方法?
124、 printf實現(xiàn)原理?
125、 #include 的順序以及尖括號和雙引號的區(qū)別
126、 lambda函數(shù)
127、 模板類和模板函數(shù)的區(qū)別是什么?
128、 為什么模板類一般都是放在一個h文件中
129、 C++中類成員的訪問權(quán)限和繼承權(quán)限問題。
130、 cout和printf有什么區(qū)別?
131、 重載運算符?
132、 函數(shù)重載函數(shù)匹配原則
133、 定義和聲明的區(qū)別
134、 全局變量和static變量的區(qū)別
135、 static函數(shù)與普通函數(shù)有什么區(qū)別?
136、 靜態(tài)成員與普通成員的區(qū)別
137、 說一下理解 ifdef endif
138、 隱式轉(zhuǎn)換,如何消除隱式轉(zhuǎn)換?
139、 虛函數(shù)的內(nèi)存結(jié)構(gòu),那菱形繼承的虛函數(shù)內(nèi)存結(jié)構(gòu)呢
140、 多繼承的優(yōu)缺點,作為一個開發(fā)者怎么看待多繼承
?
121、 怎樣判斷兩個浮點數(shù)是否相等?
對兩個浮點數(shù)判斷大小和是否相等不能直接用==來判斷,會出錯!明明相等的兩個數(shù)比較反而是不相等!對于兩個浮點數(shù)比較只能通過相減并與預(yù)先設(shè)定的精度比較,記得要取絕對值!浮點數(shù)與0的比較也應(yīng)該注意。與浮點數(shù)的表示方式有關(guān)。
const float EPSINON = 0.00001;
if (((a-b) >= - EPSINON) && ((a-b) <= EPSINON);
122、 宏定義一個取兩個數(shù)中較大值的功能
#define MAX(x,y)((x>y?)x:y)
123、 define、const、typedef、inline使用方法?
一、const與#define的區(qū)別:
1.const定義的常量是變量帶類型,而#define定義的只是個常數(shù)不帶類型;
2.define只在預(yù)處理階段起作用,簡單的文本替換,而const在編譯、鏈接過程中起作用;
3.define只是簡單的字符串替換沒有類型檢查。而const是有數(shù)據(jù)類型的,是要進行判斷的,可以避免一些低級錯誤;
4.define預(yù)處理后,占用代碼段空間,const占用數(shù)據(jù)段空間;
5.const不能重定義,而define可以通過#undef取消某個符號的定義,進行重定義;
6.define獨特功能,比如可以用來防止文件重復(fù)引用。
二、#define和別名typedef的區(qū)別
1.執(zhí)行時間不同,typedef在編譯階段有效,typedef有類型檢查的功能;#define是宏定義,發(fā)生在預(yù)處理階段,不進行類型檢查;
2.功能差異,typedef用來定義類型的別名,定義與平臺無關(guān)的數(shù)據(jù)類型,與struct的結(jié)合使用等。#define不只是可以為類型取別名,還可以定義常量、變量、編譯開關(guān)等。
3.作用域不同,#define沒有作用域的限制,只要是之前預(yù)定義過的宏,在以后的程序中都可以使用。而typedef有自己的作用域。
三、define與inline的區(qū)別
1.#define是關(guān)鍵字,inline是函數(shù);
2.宏定義在預(yù)處理階段進行文本替換,inline函數(shù)在編譯階段進行替換;
3.inline函數(shù)有類型檢查,相比宏定義比較安全;
124、 printf實現(xiàn)原理?
1.在C/C++中,對函數(shù)參數(shù)的掃描是從后向前的。C/C++的函數(shù)參數(shù)是通過壓入堆棧的方式來給函數(shù)傳參數(shù)的(堆棧是一種先進后出的數(shù)據(jù)結(jié)構(gòu)),最先壓入的參數(shù)最后出來,在計算機的內(nèi)存中,數(shù)據(jù)有2塊,一塊是堆,一塊是棧(函數(shù)參數(shù)及局部變量在這里),而棧是從內(nèi)存的高地址向低地址生長的,控制生長的就是堆棧指針了,最先壓入的參數(shù)是在高地址,最后壓入的參數(shù)在低地址,結(jié)構(gòu)上看起來是第一個,所以最后壓入的參數(shù)總是能夠被函數(shù)找到,因為它就在堆棧指針的上方。
2.printf的第一個被找到的參數(shù)就是那個字符指針,就是被雙引號括起來的那一部分,函數(shù)通過判斷字符串里控制參數(shù)的個數(shù)來判斷參數(shù)個數(shù)及數(shù)據(jù)類型,通過這些就可算出數(shù)據(jù)需要的堆棧指針的偏移量了,下面給出printf("%d,%d",a,b);(其中a、b都是int型的)的匯編代碼.
125、 #include 的順序以及尖括號和雙引號的區(qū)別
1.<>尖括號表示編譯器只在系統(tǒng)默認目錄或尖括號內(nèi)的工作目錄下搜索頭文件,并不去用戶的工作目錄下尋找,所以一般尖括號用于包含標(biāo)準庫文件;
2.""雙引號表示編譯器先在用戶的工作目錄下搜索頭文件,如果搜索不到則到系統(tǒng)默認目錄下去尋找,所以雙引號一般用于包含用戶自己編寫的頭文件。
126、 lambda函數(shù)
1.定義
利用lambda表達式可以編寫內(nèi)嵌的匿名函數(shù),用以替換獨立函數(shù)或者函數(shù)對象;每當(dāng)你定義一個lambda表達式后,編譯器會自動生成一個匿名類(這個類當(dāng)然重載了()運算符),我們稱為閉包類型(closure type)。那么在運行時,這個lambda表達式就會返回一個匿名的閉包實例,其實一個右值。可以通過傳值或者引用的方式捕捉其封裝作用域內(nèi)的變量,前面的方括號就是用來定義捕捉模式以及變量,我們又將其稱為lambda捕捉塊。
2.用法
lambda表達式的語法定義如下:
[capture list] (params list) mutable exception-> return type { function body }
各項具體含義如下:
capture list:捕獲外部變量列表
params list:形參列表
mutable指示符:用來說用是否可以修改捕獲的變量
exception:異常設(shè)定
return type:返回類型
function body:函數(shù)體
3.lamda的幾種捕獲方式
| 捕獲形式 | 說明 |
| [] | 不捕獲任何外部變量 |
| [變量名, …] | 默認以值得形式捕獲指定的多個外部變量(用逗號分隔),如果引用捕獲,需要顯示聲明(使用&說明符) |
| [this] | 以值的形式捕獲this指針 |
| [=] | 以值的形式捕獲所有外部變量 |
| [&] | 以引用形式捕獲所有外部變量 |
| [=, &x] | 變量x以引用形式捕獲,其余變量以傳值形式捕獲 |
| [&, x] | 變量x以值的形式捕獲,其余變量以引用形式捕獲 |
4.lambda必須使用尾置返回來指定返回類型,可以忽略參數(shù)列表和返回值,但必須永遠包含捕獲列表和函數(shù)體;
127、 模板類和模板函數(shù)的區(qū)別是什么?
函數(shù)模板的實例化是由編譯程序在處理函數(shù)調(diào)用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。即函數(shù)模板允許隱式調(diào)用和顯式調(diào)用而類模板只能顯示調(diào)用。在使用時類模板必須加<T>,而函數(shù)模板不必。
128、 為什么模板類一般都是放在一個h文件中
1.模板定義很特殊。由template<…>處理的任何東西都意味著編譯器在當(dāng)時不為它分配存儲空間,它一直處于等待狀態(tài)直到被一個模板實例告知。在編譯器和連接器的某一處,有一機制能去掉指定模板的多重定義。所以為了容易使用,幾乎總是在頭文件中放置全部的模板聲明和定義。
2.在分離式編譯的環(huán)境下,編譯器編譯某一個.cpp文件時并不知道另一個.cpp文件的存在,也不會去查找(當(dāng)遇到未決符號時它會寄希望于連接器)。這種模式在沒有模板的情況下運行良好,但遇到模板時就傻眼了,因為模板僅在需要的時候才會實例化出來,所以,當(dāng)編譯器只看到模板的聲明時,它不能實例化該模板,只能創(chuàng)建一個具有外部連接的符號并期待連接器能夠?qū)⒎柕牡刂窙Q議出來。然而當(dāng)實現(xiàn)該模板的.cpp文件中沒有用到模板的實例時,編譯器懶得去實例化,所以,整個工程的.obj中就找不到一行模板實例的二進制代碼,于是連接器也黔驢技窮了。
129、 C++中類成員的訪問權(quán)限和繼承權(quán)限問題。
一、三種訪問權(quán)限
○1public:用該關(guān)鍵字修飾的成員表示公有成員,該成員不僅可以在類內(nèi)可以被 訪問,在類外也是可以被訪問的,是類對外提供的可訪問接口;
○2private:用該關(guān)鍵字修飾的成員表示私有成員,該成員僅在類內(nèi)可以被訪問,在類體外是隱藏狀態(tài);
○3protected:用該關(guān)鍵字修飾的成員表示保護成員,保護成員在類體外同樣是隱藏狀態(tài),但是對于該類的派生類來說,相當(dāng)于公有成員,在派生類中可以被訪問。
二、三種繼承方式
○1若繼承方式是public,基類成員在派生類中的訪問權(quán)限保持不變,也就是說,基類中的成員訪問權(quán)限,在派生類中仍然保持原來的訪問權(quán)限;
○2若繼承方式是private,基類所有成員在派生類中的訪問權(quán)限都會變?yōu)樗接?private)權(quán)限;
○3若繼承方式是protected,基類的共有成員和保護成員在派生類中的訪問權(quán)限都會變?yōu)楸Wo(protected)權(quán)限,私有成員在派生類中的訪問權(quán)限仍然是私有(private)權(quán)限。
130、 cout和printf有什么區(qū)別?
cout<<是一個函數(shù),cout<<后可以跟不同的類型是因為cout<<已存在針對各種類型數(shù)據(jù)的重載,所以會自動識別數(shù)據(jù)的類型。輸出過程會首先將輸出字符放入緩沖區(qū),然后輸出到屏幕。
cout是有緩沖輸出:cout << "abc " <<endl;或cout << "abc\n ";cout < <flush; 這兩個才是一樣的。endl相當(dāng)于輸出回車后,再強迫緩沖輸出。flush立即強迫緩沖輸出。printf是無緩沖輸出。有輸出時立即輸出(lsy注:在嵌入式里盡量不用用printf打印信息,耗時!)
131、 重載運算符?
1、我們只能重載已有的運算符,而無權(quán)發(fā)明新的運算符;對于一個重載的運算符,其優(yōu)先級和結(jié)合律與內(nèi)置類型一致才可以;不能改變運算符操作數(shù)個數(shù);
2、這幾種 . :: ?: sizeof typeid ** 不能重載;
3、兩種重載方式,成員運算符和非成員運算符,成員運算符比非成員運算符少一個參數(shù);
4、下標(biāo)運算符、箭頭運算符必須是成員運算符;
5、引入運算符重載,是為了實現(xiàn)類的多態(tài)性;
6、當(dāng)重載的運算符是成員函數(shù)時,this綁定到左側(cè)運算符對象。成員運算符函數(shù)的參數(shù)數(shù)量比運算符對象的數(shù)量少一個;至少含有一個類類型的參數(shù);
7、從參數(shù)的個數(shù)推斷到底定義的是哪種運算符,當(dāng)運算符既是一元運算符又是二元運算符(+,-,*,&);
8、下標(biāo)運算符必須是成員函數(shù),下標(biāo)運算符通常以所訪問元素的引用作為返回值,同時最好定義下標(biāo)運算符的常量版本和非常量版本;
9、箭頭運算符必須是類的成員,解引用通常也是類的成員;重載的箭頭運算符必須返回類的指針;
132、 函數(shù)重載函數(shù)匹配原則
將函數(shù)匹配分為三個階段,確定候選函數(shù),確定可行函數(shù),確定最佳匹配函數(shù)。
1.確定候選函數(shù):需要和被調(diào)用的函數(shù)同名,并且其聲明在調(diào)用點可見。
2.確定可行函數(shù):本次調(diào)用傳入的實參能夠被候選函數(shù)使用。它要滿足兩個條件,一是形參數(shù)量和實參數(shù)量相同,二是每個實參的類型和對應(yīng)形參類型相同或者能夠轉(zhuǎn)換成形參的類型。
3.尋找最佳匹配:最佳匹配最基本的思想是認為,實參類型越接近,它們就越匹配。
133、 定義和聲明的區(qū)別
1.如果是指變量的聲明和定義從編譯原理上來說,聲明是僅僅告訴編譯器,有個某類型的變量會被使用,但是編譯器并不會為它分配任何內(nèi)存。而定義就是分配了內(nèi)存。
2.如果是指函數(shù)的聲明和定義聲明:一般在頭文件里,對編譯器說:這里我有一個函數(shù)叫function()讓編譯器知道這個函數(shù)的存在。定義:一般在源文件里,具體就是函數(shù)的實現(xiàn)過程 寫明函數(shù)體。
134、 全局變量和static變量的區(qū)別
1、全局變量(外部變量)的說明之前再冠以static就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲方式,靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲方式。
2.這兩者在存儲方式上并無不同。這兩者的區(qū)別在于非靜態(tài)全局變量的作用域是整個源程序,當(dāng)一個源程序由多個原文件組成時,非靜態(tài)的全局變量在各個源文件中都是有效的。而靜態(tài)全局變量則限制了其作用域,即只在定義該變量的源文件內(nèi)有效,在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域限于一個源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其他源文件中引起錯誤。static全局變量與普通的全局變量的區(qū)別是static全局變量只初始化一次,防止在其他文件單元被引用。
135、 static函數(shù)與普通函數(shù)有什么區(qū)別?
在函數(shù)的返回類型前加上關(guān)鍵字static,函數(shù)就被定義成為靜態(tài)函數(shù)。普通函數(shù)的定義和聲明默認情況下是extern的,但靜態(tài)函數(shù)被限定在源碼文件中,只在聲明他的文件當(dāng)中可見,不能被其他文件所用。
普通函數(shù):
static函數(shù)與普通函數(shù)有什么區(qū)別:static函數(shù)在內(nèi)存中只有一份,普通函數(shù)在每個被調(diào)用中維持一份拷貝。
類成員函數(shù):
區(qū)別1:靜態(tài)成員函數(shù)實際上是一個全局函數(shù),不依賴一個類的對象,屬于類,不創(chuàng)建對象也可調(diào)用。
普通成員函數(shù)依賴一個類的對象,也就是它有一個隱藏的調(diào)用參數(shù)(this)指針,必須指向一個類的對象。
區(qū)別2:靜態(tài)函數(shù)只能訪問類中的靜態(tài)成員變量;
區(qū)別3:如果類的成員函數(shù)想作為回調(diào)函數(shù)來使用,如創(chuàng)建線程等,一般只能將它定義為靜態(tài)成員函數(shù)才行。
定義靜態(tài)函數(shù)有以下好處:
<1> 其他文件中可以定義相同名字的函數(shù),不會發(fā)生沖突。
<2> 靜態(tài)函數(shù)不能被其他文件所用。
136、 靜態(tài)成員與普通成員的區(qū)別
1.生命周期
靜態(tài)成員變量從類被加載開始到類被卸載,一直存在;
普通成員變量只有在類創(chuàng)建對象后才開始存在,對象結(jié)束,它的生命期結(jié)束;
2.共享方式
靜態(tài)成員變量是全類共享;普通成員變量是每個對象單獨享用的;
3.定義位置
普通成員變量存儲在棧或堆中,而靜態(tài)成員變量存儲在靜態(tài)全局區(qū);
4.初始化位置
普通成員變量在類中初始化;靜態(tài)成員變量在類外初始化;
5.默認實參
可以使用靜態(tài)成員變量作為默認實參,
137、 說一下理解 ifdef endif
1.一般情況下,源程序中所有的行都參加編譯。但是有時希望對其中一部分內(nèi)容只在滿足一定條件才進行編譯,也就是對一部分內(nèi)容指定編譯的條件,這就是“條件編譯”。有時,希望當(dāng)滿足某條件時對一組語句進行編譯,而當(dāng)條件不滿足時則編譯另一組語句。
2.條件編譯命令最常見的形式為:
#ifdef 標(biāo)識符
程序段1
#else
程序段2
#endif
它的作用是:當(dāng)標(biāo)識符已經(jīng)被定義過(一般是用#define命令定義),則對程序段1進行編譯,否則編譯程序段2。其中#else部分也可以沒有,即:#ifdef
程序段1
#denif
3.在一個大的軟件工程里面,可能會有多個文件同時包含一個頭文件,當(dāng)這些文件編譯鏈接成一個可執(zhí)行文件上時,就會出現(xiàn)大量“重定義”錯誤。在頭文件中使用#define、#ifndef、#ifdef、#endif能避免頭文件重定義。
138、 隱式轉(zhuǎn)換,如何消除隱式轉(zhuǎn)換?
1.C++的基本類型中并非完全的對立,部分數(shù)據(jù)類型之間是可以進行隱式轉(zhuǎn)換的。所謂隱式轉(zhuǎn)換,是指不需要用戶干預(yù),編譯器私下進行的類型轉(zhuǎn)換行為。很多時候用戶可能都不知道進行了哪些轉(zhuǎn)換
2.C++面向?qū)ο蟮亩鄳B(tài)特性,就是通過父類的類型實現(xiàn)對子類的封裝。通過隱式轉(zhuǎn)換,你可以直接將一個子類的對象使用父類的類型進行返回。在比如,數(shù)值和布爾類型的轉(zhuǎn)換,整數(shù)和浮點數(shù)的轉(zhuǎn)換等。某些方面來說,隱式轉(zhuǎn)換給C++程序開發(fā)者帶來了不小的便捷。C++是一門強類型語言,類型的檢查是非常嚴格的。
3.基本數(shù)據(jù)類型,基本數(shù)據(jù)類型的轉(zhuǎn)換以取值范圍的作為轉(zhuǎn)換基礎(chǔ)(保證精度不丟失)。隱式轉(zhuǎn)換發(fā)生在從小->大的轉(zhuǎn)換中。比如從char轉(zhuǎn)換為int。從int->long。自定義對象 子類對象可以隱式的轉(zhuǎn)換為父類對象。
4.C++中提供了explicit關(guān)鍵字,在構(gòu)造函數(shù)聲明的時候加上explicit關(guān)鍵字,能夠禁止隱式轉(zhuǎn)換。
5.如果構(gòu)造函數(shù)只接受一個參數(shù),則它實際上定義了轉(zhuǎn)換為此類類型的隱式轉(zhuǎn)換機制。可以通過將構(gòu)造函數(shù)聲明為explicit加以制止隱式類型轉(zhuǎn)換,關(guān)鍵字explicit只對一個實參的構(gòu)造函數(shù)有效,需要多個實參的構(gòu)造函數(shù)不能用于執(zhí)行隱式轉(zhuǎn)換,所以無需將這些構(gòu)造函數(shù)指定為explicit。
139、 虛函數(shù)的內(nèi)存結(jié)構(gòu),那菱形繼承的虛函數(shù)內(nèi)存結(jié)構(gòu)呢
菱形繼承的定義是:兩個子類繼承同一父類,而又有子類同時繼承這兩個子類。例如a,b兩個類同時繼承c,但是又有一個d類同時繼承a,b類。
lsy注:由于這部分內(nèi)容太多,一定移步博客:(講解深入淺出,推薦!最開始不知道怎么搞了個vip可看,又取消不了,可能后續(xù)會重寫,如果你在看這篇文檔的時候發(fā)現(xiàn)還不能看,就聯(lián)系我)
https://blog.csdn.net/qq_41687938/article/details/120487045
140、 多繼承的優(yōu)缺點,作為一個開發(fā)者怎么看待多繼承
1.C++允許為一個派生類指定多個基類,這樣的繼承結(jié)構(gòu)被稱做多重繼承。
2.多重繼承的優(yōu)點很明顯,就是對象可以調(diào)用多個基類中的接口;
3.如果派生類所繼承的多個基類有相同的基類,而派生類對象需要調(diào)用這個祖先類的接口方法,就會容易出現(xiàn)二義性
4.加上全局符確定調(diào)用哪一份拷貝。比如pa.Author::eat()調(diào)用屬于Author的拷貝。
5.使用虛擬繼承,使得多重繼承類Programmer_Author只擁有Person類的一份拷貝。
總結(jié)
以上是生活随笔為你收集整理的二十万字C/C++、嵌入式软开面试题全集宝典七的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: google地图 离线版 经纬度_一款钓
- 下一篇: 双目估计方法_教你提高双目立体视觉系统的