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)
|
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) order. The
functions passed to _onexit cannot take parameters.
備註: 1.使用_onexit註冊方法不能有返回值; 2.根據註冊的先後順序,按照棧規則(後進先出),從後向前執行。 |
40.如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的?
答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif