C++面試寶典(整理版)2


21.多態的作用?

主要是兩個:

1. 隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用;

2. 接口重用:爲了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用。


22.Ado與Ado.net的相同與不同?

除了“能夠讓應用程序處理存儲於DBMS中的數據“這一基本相似點外,兩者沒有太多共同之處。但是Ado使用OLE DB 接口並基於微軟的COM技術,而ADO.NET 擁有自己的ADO.NET 接口並且基於微軟的.NET體系架構。衆所周知.NET 體系不同於COM 體系,ADO.NET接口也就完全不同於ADO和OLE DB 接口,這也就是說ADO.NET和ADO是兩種數據訪問方式。ADO.net 提供對XML的支持。


23.New delete 與malloc free 的聯繫與區別? 

答案:都是在(heap)上進行動態的內存操作。用malloc函數需要指定內存分配的字節數並且不能初始化對象,new 會自動調用對象的構造函數。delete 會調用對象的destructor,而free 不會調用對象的destructor.    


24.#define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?

答案:i 爲30。

考察#define的作用,文本替換。表達式 i = 5 * DOUBLE(5) 替換之後的表達式是 i = 5 * 5 + 5 = 30


25.有哪幾種情況只能用intialization list 而不能用assignment?

答案:當類中含有const、reference成員變量;基類的構造函數都需要初始化表

const變量和“引用”只有在初始化的時候可以賦值


26. C++是不是類型安全的?

答案:不是兩個不同類型的指針之間可以強制轉換(用reinterpret cast)。C#是類型安全的。


27. main 函數執行以前,還會執行什麼代碼?

答案:全局對象的構造函數會在main 函數之前執行。


28. 描述內存分配方式以及它們的區別?

1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static變量
2) 在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集。
3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多。

按照實現代碼位置區分
全局變量,單元文件內。
局部變量(棧),函數內臨時變量。
動態申請(堆),手動申請(需要釋放的內存)


29.struct 和 class 的區別

答案:struct 的成員默認是公有的,而類的成員默認是私有的。struct和 class 在其他方面是功能相當的。從感情上講,大多數的開發者感到類和結構有很大的差別。感覺上結構僅僅象一堆缺乏封裝和功能的開放的內存位,而類就象活的並且可靠的社會成員,它有智能服務,有牢固的封裝屏障和一個良好定義的接口。既然大多數人都這麼認爲,那麼只有在你的類有很少的方法並且有公有數據(這種事情在良好設計的系統中是存在的!)時,你也許應該使用 struct 關鍵字,否則,你應該使用 class 關鍵字。


30.當一個類A 中沒有任何成員變量與成員函數,這時sizeof(A)的值是多少?

答案:如果不是零,請解釋一下編譯器爲什麼沒有讓它爲零。(Autodesk)肯定不是零。舉個反例,如果是零的話,聲明一個class A[10]對象數組,而每一個對象佔用的空間是零,這時就沒辦法區分A[0],A[1]…了。


31. 在8086 彙編下,邏輯地址和物理地址是怎樣轉換的?(Intel)

答案:通用寄存器給出的地址,是段內偏移地址,相應段寄存器地址*10H+通用寄存器內地址,就得到了真正要訪問的地址。

物理地址 = 段寄存器地址 * 段大小 + 通用寄存器地址(個人理解)


32. 比較C++中的4種類型轉換方式

重點是static_cast, dynamic_cast和reinterpret_cast的區別和應用。

dynamic_casts在幫助你瀏覽繼承層次上是有限制的。它不能被用於缺乏虛函數的類型上,它被用於安全地沿着類的繼承關係向下進行類型轉換。如你想在沒有繼承關係的類型中進行轉換,你可能想到static_cast。

ANSI-C++標準定義了四個新的轉換符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast',目的在於控制類(class)之間的類型轉換。
代碼:
reinterpret_cast<new_type>(expression)
dynamic_cast<new_type>(expression)
static_cast<new_type>(expression)
const_cast<new_type>(expression)
  • dynamic_cast 主要用於執行“安全的向下轉型(safe downcasting)”,也就是說,要確定一個對象是否是一個繼承體系中的一個特定類型。
  • static_cast 可以被用於強制隱型轉換(例如,non-const 對象轉型爲 const 對象,int 轉型爲 double,等等),它還可以用於很多這樣的轉換的反向轉換(例如,void* 指針轉型爲有類型指針,基類指針轉型爲派生類指針),但是它不能將一個 const 對象轉型爲 non-const 對象(只有 const_cast 能做到)。
  • const_cast 一般用於強制消除對象的常量性。它是唯一能做到這一點的 C++ 風格的強制轉型。
  • reinterpret_cast 是特意用於底層的強制轉型,導致實現依賴(implementation-dependent)(就是說,不可移植)的結果,例如,將一個指針轉型爲一個整數。


33.分別寫出BOOL,int,float,指針類型的變量a 與“零”的比較語句。

答案:
BOOL :    if ( !a ) or if(a)
int :     if ( a == 0)
float :   const EXPRESSION EXP = 0.000001
          if ( a < EXP && a>-EXP)

pointer : if ( a != NULL) or if(a == NULL)    【更優方式: if ( NULL != a) or if ( NULL == a)

 


34.請說出const與#define 相比,有何優點?

答案:

Const作用:定義常量、修飾函數參數、修飾函數返回值三個作用。被Const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性

1) const 常量有數據類型,而宏常量沒有數據類型編譯器可以對前者進行類型安全檢查。而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤。
2) 有些集成化的調試工具可以對const常量進行調試,但是不能對宏常量進行調試。


35.簡述數組與指針的區別?

數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。
(1)修改內容上的差別
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字符串
p[0] = ‘X’; // 編譯器不能發現該錯誤,運行時錯誤
(2) 用運算符sizeof 可以計算出數組的容量(字節數)。sizeof(p),p 爲指針得到的是一個指針變量的字節數,而不是p 所指的內存容量。C++/C 語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它注意當數組作爲函數的參數進行傳遞時,該數組自動退化爲同類型的指針
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字節
cout<< sizeof(p) << endl; // 4 字節
計算數組和指針的內存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字節而不是100字節
}


36.類成員函數的重載、覆蓋和隱藏區別?

答案:

a.成員函數被重載的特徵
(1)相同的範圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;

(4)virtual 關鍵字可有可無。
b.覆蓋是指派生類函數覆蓋基類函數,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函數名字相同;
(3)參數相同;

(4)基類函數必須有virtual 關鍵字。
 c.“隱藏”是指派生類的函數屏蔽了與其同名基類函數,規則如下:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)



37.求出兩個數中的較大值

There are two int variables:a and b, don’t use “if”, “? :”, “switch”or other judgement statements, find outthe biggest one of the two numbers.

答案:( ( a + b ) + abs( a - b ) ) / 2

數學推理原理暫無法證明
代入數值驗證,a=1,b=2,結果=2;a=3,b=2,結果=3



38.如何打印出當前源文件的文件名以及源文件的當前行號?

答案:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系統預定義宏,這種宏並不是在某個文件中定義的,而是由編譯器定義的。


39. main 主函數執行完畢後,是否可能會再執行一段代碼,給出說明?

答案:可以,可以用_onexit 註冊一個函數,它會在main之後執行int fn1(void), fn2(void),fn3(void), fn4 (void);
void main( void )
{
String str("zhanglin");
_onexit( fn1 );
_onexit( fn2 );
_onexit( fn3 );
_onexit( fn4 );
printf( "This is executed first.n" );
}
int fn1()
{
printf( "next.n" );
return 0;
}
int fn2()
{
printf( "executed " );
return 0;
}
int fn3()
{
printf( "is " );
return 0;
}
int fn4()
{
printf( "This " );
return 0;
}
The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create aregister of functions that are executed in LIFO (last-in-first-out) orderThe functions passed to _onexit cannot take parameters.

 備註:
1.使用_onexit註冊方法不能有返回值;
2.根據註冊的先後順序,按照棧規則(後進先出),從後向前執行。


40.如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的?

答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif



發佈了23 篇原創文章 · 獲贊 10 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章