1. 程式人生 > >c++必懂的基本概念

c++必懂的基本概念

1.   面向物件的程式設計思想是什麼?

答:把資料結構和對資料結構進行操作的方法封裝形成一個個的物件。

2.   什麼是類?

答:把一些具有共性的物件歸類後形成一個集合,也就是所謂的類。

3.   物件都具有的二方面特徵是什麼?分別是什麼含義?

答:物件都具有的特徵是:靜態特徵和動態特徵

靜態特徵是指能描述物件的一些屬性;

動態特徵是指物件表現出來的行為 ;

4.   在標頭檔案中進行類的宣告,在對應的實現檔案中進行類的定義有什麼意義?

答:1這樣可以提高編譯效率,因為分開的話只需要編譯一次生成對應的.obj檔案後,再次應用該類的地方,這個類就不會被再次編譯,從而大大提高了效率。

      2隱藏了程式碼;

5.   在類的內部定義成員函式的函式體,這種函式會具備那種屬性?

答:這種函式會自動為行內函數,這種函式在函式呼叫的地方在編譯階段都會進行程式碼替換。

6.   成員函式通過什麼來區分不同物件的成員資料?為什麼它能夠區分?

答:通過this指標來區分的, 因為它指向的是物件的首地址。

7.   C++編譯器自動為類產生的四個預設函式是什麼?

答:預設建構函式(不帶引數的建構函式),拷貝建構函式(用於物件間的賦值),解構函式,賦值函式(等號的賦值)。

8.   拷貝建構函式在哪幾種情況下會被呼叫?

答:1.當類的一個物件去初始化該類的另一個物件時;

2.如果函式的形參是類的物件,呼叫函式進行形參和實參結合時;

3.如果函式的返回值是類物件,函式呼叫完成返回時。

9.   建構函式與普通函式相比在形式上有什麼不同?(建構函式的作用,它的宣告形式來分析)

答:建構函式是類的一種特殊成員函式,一般情況下,它是專門用來初始化物件成員變數的。

建構函式的名字必須與類名相同,它不具有任何型別,不返回任何值。

10.  什麼時候必須重寫拷貝建構函式?

答:當建構函式涉及到動態儲存分配空間時,要自己寫拷貝建構函式,並且要深拷貝。

11. 建構函式的呼叫順序是什麼?

答:1.先呼叫基類建構函式

   2.按宣告順序初始化資料成員

3.最後呼叫自己的建構函式。

12.  哪幾種情況必須用到初始化成員列表?

答:類的成員是常量成員初始化;

類的成員是物件成員初始化,而該物件沒有無參建構函式。

類的成員常變數時。

13.  什麼是常物件?

答:常物件是指在任何場合都不能對其成員的值進行修改的物件。

14.  靜態函式存在的意義?

答:1靜態私有成員在類外不能被訪問,可通過類的靜態成員函式來訪問;

2當類的建構函式是私有的時,不像普通類那樣例項化自己,只能通過靜態成員函式來呼叫建構函式。

15.  在類外有什麼辦法可以訪問類的非公有成員?

答:友元,繼承,公有成員函式。

16.  什麼叫抽象類?

答:不用來定義物件而只作為一種基本型別用作繼承的類。

17.  運算子過載的意義?

答:為了對使用者自定義資料型別的資料的操作與內定義的資料型別的資料的操作形式一致。

18.  不允許過載的5個運算子是哪些?

答:

1.   .*(成員指標訪問運算子號)

2.   ::域運算子

3.   sizeof 長度運算子號

4.   ?:條件運算子號

5. .(成員訪問符)

19.  運算子過載的三種方式?

答:普通函式,友元函式,類成員函式。

20.  流運算子為什麼不能通過類的成員函式過載?一般怎麼解決?

答:因為通過類的成員函式過載必須是運算子的第一個是自己,而對流運算的過載要求第一個引數是流物件。一般通過友元來解決。

21.  賦值運算子和拷貝建構函式的區別與聯絡?

答:相同點:都是將一個物件copy到另一箇中去。

不同點:拷貝建構函式涉及到要新建立一個物件。

22.  在哪種情況下要呼叫該類的解構函式?

答:物件生命週期結束時。

23.  物件間是怎樣實現資料的共享的?

答:通過類的靜態成員變數來實現的。靜態成員變數佔有自己獨立的空間不為某個物件所私有。

24.  友元關係有什麼特性?

答:單向的,非傳遞的,不能繼承的。

25.  對 物件成員進行初始化的次序是什麼?

答:它的次序完全不受它們在初始化表中次序的影響,只與成員物件在類中宣告的次序來決定的。

26.  類和物件之間的關係是什麼?

答:類是物件的抽象,物件是類的例項。

27.  對類的成員的訪問屬性有什麼?

答:public,protected,private。

28.    const char *p,  char *const p;的區別

如果const位於星號的左側,則const就是用來修飾指標所指向的變數,即指標指向為常量;

如果const位於星號的右側,const就是修飾指標本身,即指標本身是常量。

29.  是不是一個父類寫了一個virtual 函式,如果子類覆蓋它的函式不加virtual ,也能實現多型?

virtual修飾符會被隱形繼承的。

virtual可加可不加,子類覆蓋它的函式不加virtual ,也能實現多型。

127.類成員函式的過載、覆蓋和隱藏區別

答案:

成員函式被過載的特徵:

(1)相同的範圍(在同一個類中);

(2)函式名字相同;

(3)引數不同;

(4)virtual 關鍵字可有可無。

覆蓋是指派生類函式覆蓋基類函式,特徵是:

(1)不同的範圍(分別位於派生類與基類);

(2)函式名字相同;

(3)引數相同;

(4)基類函式必須有virtual 關鍵字。

“隱藏”是指派生類的函式遮蔽了與其同名的基類函式,規則如下:

(1)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。

(2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)

30.  函式過載是什麼意思?它與虛擬函式的概念有什麼區別?

函式過載是一個同名函式完成不同的功能,編譯系統在編譯階段通過函式引數個數、引數型別不同,即實現的是靜態的多型性。但是記住:不能僅僅通過函式返回值不同來實現函式過載。而虛擬函式實現的是在基類中通過使用關鍵字virtual來申明一個函式為虛擬函式,含義就是該函式的功能可能在將來的派生類中定義或者在基類的基礎之上進行擴充套件,系統只能在執行階段才能動態決定該呼叫哪一個函式,所以實現的是動態的多型性。它體現的是一個縱向的概念,也即在基類和派生類間實現。

31.  建構函式和解構函式是否可以被過載,為什麼?

答:建構函式可以被過載,解構函式不可以被過載。因為建構函式可以有多個且可以帶引數,而解構函式只能有一個,且不能帶引數。

32.  如何定義和實現一個類的成員函式為回撥函式?

答:

所謂的回撥函式,就是預先在系統對函式進行註冊,讓系統知道這個函式的存在,以後,當某個事件發生時,再呼叫這個函式對事件進行響應。

定義一個類的成員函式時在該函式名前加CALLBACK即將其定義為回撥函式,函式的實現和普通成員函式沒有區別

33.  虛擬函式是怎麼實現的?

答:簡單說來使用了虛擬函式表.

34.  抽象類不會產生例項,所以不需要有建構函式。 錯

35.  從一個模板類可以派生新的模板類,也可以派生非模板類。 對

36.  main 函式執行以前,還會執行什麼程式碼?

答案:全域性物件的建構函式會在main 函式之前執行。

37.  當一個類A 中沒有生命任何成員變數與成員函式,這時sizeof(A)的值是多少,如果不是零,請解釋一下編譯器為什麼沒有讓它為零。(Autodesk)

答案:肯定不是零。舉個反例,如果是零的話,宣告一個class A[10]物件陣列,而每一個物件佔用的空間是零,這時就沒辦法區分A[0],A[1]…了。

38.  delete與 delete []區別:

delete只會呼叫一次解構函式,而delete[]會呼叫每一個成員的解構函式。

39.    子類析構時要呼叫父類的解構函式嗎?

會呼叫,解構函式呼叫的次序是先派生類的析構後基類的析構,也就是說在基類的的析構呼叫的時候,派生類的資訊已經全部銷燬了

**************************************************************************

40. 繼承優缺點。

1、類繼承是在編譯時刻靜態定義的,且可直接使用,

2、類繼承可以較方便地改變父類的實現。

缺點:

1、因為繼承在編譯時刻就定義了,所以無法在執行時刻改變從父類繼承的實現

2、父類通常至少定義了子類的部分行為,父類的任何改變都可能影響子類的行為

3、如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。

41.  解釋堆和棧的區別。

棧區(stack)—  由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。

堆:一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收 。

42.  一個類的建構函式和解構函式什麼時候被呼叫,是否需要手工呼叫?

答:建構函式在建立類物件的時候被自動呼叫,解構函式在類物件生命期結束時,由系統自動呼叫。

43.  何時需要預編譯:

總是使用不經常改動的大型程式碼體。

程式由多個模組組成,所有模組都使用一組標準的包含檔案和相同的編譯選項。在這種情況下,可以將所有包含檔案預編譯為一個預編譯頭。

44.  多型的作用?

主要是兩個:

1. 隱藏實現細節,使得程式碼能夠模組化;擴充套件程式碼模組,實現程式碼重用;

2. 介面重用:為了類在繼承和派生的時候,保證使用家族中任一類的例項的某一屬性時的正確呼叫

45.  虛擬函式與普通成員函式的區別?行內函數和建構函式能否為虛擬函式?

答案:區別:虛擬函式有virtual關鍵字,有虛擬指標和虛擬函式表,虛擬指標就是虛擬函式的介面,而普通成員函式沒有。行內函數和建構函式不能為虛擬函式。

46.  建構函式和解構函式的呼叫順序? 解構函式為什麼要虛擬?

答案:建構函式的呼叫順序:基類建構函式—物件成員建構函式—派生類建構函式;解構函式的呼叫順序與建構函式相反。解構函式虛擬是為了防止析構不徹底,造成記憶體的洩漏。

47.  C++中型別為private的成員變數可以由哪些函式訪問?

只可以由本類中的成員函式和友員函式訪問

48.  請說出類中private,protect,public三種訪問限制類型的區別

private是私有型別,只有本類中的成員函式訪問;protect是保護型的,本類和繼承類可以訪問;public是公有型別,任何類都可以訪問.

49.  類中成員變數怎麼進行初始化?

可以通過建構函式的初始化列表或建構函式的函式體實現。

50.  在什麼時候需要使用“常引用”? 

如果既要利用引用提高程式的效率,又要保護傳遞給函式的資料不在函式中被改變,就應使用常引用。

51.  引用與指標有什麼區別?

答 、1) 引用必須被初始化,指標不必。

2) 引用初始化以後不能被改變,指標可以改變所指的物件。

3) 不存在指向空值的引用,但是存在指向空值的指標。

52.  描述實時系統的基本特性

      答 、在特定時間內完成特定的任務,實時性與可靠性。

54.  全域性變數和區域性變數在記憶體中是否有區別?如果有,是什麼區別?

答 、全域性變數儲存在靜態資料區,區域性變數在棧中。

55.  堆疊溢位一般是由什麼原因導致的?

答 、沒有回收垃圾資源

56.  什麼函式不能宣告為虛擬函式?

答 建構函式(constructor)

57.  .IP地址的編碼分為哪倆部分?

答 IP地址由兩部分組成,網路號和主機號。

58.  .不能做switch()的引數型別是:

答 、switch的引數不能為實型。(****** 什麼是實型)

59.  如何引用一個已經定義過的全域性變數?

答 、可以用引用標頭檔案的方式,也可以用extern關鍵字,如果用引用標頭檔案方式來引用某個在標頭檔案中宣告的全域性變數,假定你將那個變數寫錯了,那麼在編譯期間會報錯,如果你用extern方式引用時,假定你犯了同樣的錯誤,那麼在編譯期間不會報錯,而在連線期間報錯

60.  對於一個頻繁使用的短小函式,在C語言中應用什麼實現,在C++中應用什麼實現?

答 、c用巨集定義,c++用inline

61.  C++是不是型別安全的?

答案:不是。兩個不同型別的指標之間可以強制轉換(用reinterpret cast)

int a=0x11223344;

      int *b=&a;

      char *c=(char*)b;

      printf("%xn",*c);

63.  簡述陣列與指標的區別?

陣列要麼在靜態儲存區被建立(如全域性陣列),要麼在棧上被建立。

指標可以隨時指向任意型別的記憶體塊。

(1)修改內容上的區別

char a[] = “hello”;

a[0] = ‘X’;

char *p = “world”; // 注意p 指向常量字串

p[0] = ‘X’; // 編譯器不能發現該錯誤,執行時錯誤 (******************)

(2) 用運算子sizeof 可以計算出陣列的容量(位元組數)。sizeof(p),p 為指標得到的是一個指標變數的位元組數,而不是p 所指的記憶體容量。

64.  C++函式中值的傳遞方式

有三種方式:值傳遞、指標傳遞、引用傳遞

65.  記憶體的分配方式

分配方式有三種,

 1、 靜態儲存區,是在程式編譯時就已經分配好的,在整個執行期間都存在,如全域性變數、常量。

2、 棧上分配,函式內的區域性變數就是從這分配的,但分配的記憶體容易有限。

3、 堆上分配,也稱動態分配,如我們用new,malloc分配記憶體,用delete,free來釋放的記憶體。

66.  extern“C”有什麼作用?

extern “C”是由C++提供的一個連線交換指定符號,用於告訴C++這段程式碼是C函式。這是因為C++編譯後庫中函式名會變得很長,與C生成的不一致,造成C++不能直接呼叫C函式,加上extren “c”後,C++就能直接呼叫C函數了。

extern “C”主要使用正規DLL函式的引用和匯出 和 在C++包含C函式或C標頭檔案時使用。使用時在前面加上extern “c” 關鍵字即可。

67.  用什麼函式開啟新程序、執行緒。

答案:

執行緒:CreateThread/AfxBeginThread等

程序:CreateProcess等

68.  SendMessage和PostMessage有什麼區別

答案:SendMessage是阻塞的,等訊息被處理後,程式碼才能走到SendMessage的下一行。PostMessage是非阻塞的,不管訊息是否已被處理,程式碼馬上走到PostMessage的下一行。

69.  CMemoryState主要功能是什麼

答案:檢視記憶體使用情況,解決記憶體洩露問題。

70.  26、#include <filename.h> 和 #include “filename.h” 有什麼區別?

答:對於#include <filename.h> ,編譯器從標準庫路徑開始搜尋 filename.h

對於#include “filename.h” ,編譯器從使用者的工作路徑開始搜尋 filename.h

71.  處理器標識#error的目的是什麼?

答:編譯時輸出一條錯誤資訊,並中止繼續編譯。

72.  #if!defined(AFX_…_HADE_H)

#define(AFX_…_HADE_H)

……

#endif作用?

防止該標頭檔案被重複引用。

73. 在定義一個巨集的時候要注意什麼?

      定義部分的每個形參和整個表示式都必須用括號括起來,以避免不可預料的錯誤發生

74.  陣列在做函式實參的時候會轉變為什麼型別?

陣列在做實參時會變成指標型別。

75.  系統會自動開啟和關閉的3個標準的檔案是?

(1)  標準輸入----鍵盤---stdin

(2)  標準輸出----顯示器---stdout

(3)  標準出錯輸出----顯示器---stderr

76.  .在Win32下 char, int, float, double各佔多少位?

(1)  Char      佔用8位

(2)  Int 佔用32位

(3)  Float 佔用32位

(4)  Double 佔用64位

77.  strcpy()和memcpy()的區別?

      strcpy()和memcpy()都可以用來拷貝字串,strcpy()拷貝以’’結束,但memcpy()必須指定拷貝的長度。

78.  說明define和const在語法和含義上有什麼不同?

(1)  #define是C語法中定義符號變數的方法,符號常量只是用來表達一個值,在編譯階段符號就被值替換了,它沒有型別;

(2)  Const是C++語法中定義常變數的方法,常變數具有變數特性,它具有型別,記憶體中存在以它命名的儲存單元,可以用sizeof測出長度。

79.  說出字元常量和字串常量的區別,並使用運算子sizeof計算有什麼不用?

字元常量是指單個字元,字串常量以‘’結束,使用運算子sizeof計算多佔一位元組的儲存空間。

80.  簡述全域性變數的優缺點?

全域性變數也稱為外部變數,它是在函式外部定義的變數,它屬於一個源程式檔案,它儲存上一次被修改後的值,便於資料共享,但不方便管理,易引起意想不到的錯誤。

81.  總結static的應用和作用?(**************************)

(1)函式體內static變數的作用範圍為該函式體,不同於auto變數,該變數的記憶體只被分配一次,因此其值在下次呼叫時仍維持上次的值;

void fun1()

{

      static int a = 0;

      int b = 0;

      int sum_a = 0;

      sum_a = sum_a + a++;

      int sum_b = 0;

      sum_b =sum_b + b++;

      cout << sum_a << "    " << sum_b << endl;

}

int main(int argc, char* argv[])

{

      int i = 0;

      while( i < 10 )

      {

             fun1();

             i++;

      }

      return 0;

} // 這個例子中 sum_a 是一直在累加。而sum_b 一直是0

(2)在模組內的static全域性變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問;

(3)在模組內的static函式只可被這一模組內的其它函式呼叫,這個函式的使用範圍被限制在宣告它的模組內;

(4)在類中的static成員變數屬於整個類所擁有,對類的所有物件只有一份拷貝;

(5)在類中的static成員函式屬於整個類所擁有,這個函式不接收this指標,因而只能訪問類的static成員變數。

82.  .總結const的應用和作用?(**************************)

(1)欲阻止一個變數被改變,可以使用const關鍵字。在定義該const變數時,通常需要對它進行初始化,因為以後就沒有機會再去改變它了;

(2)對指標來說,可以指定指標本身為const,也可以指定指標所指的資料為const,或二者同時指定為const;

(3)在一個函式宣告中,const可以修飾形參,表明它是一個輸入引數,在函式內部不能改變其值;

(4)對於類的成員函式,若指定其為const型別,則表明其是一個常函式,不能修改類的成員變數;void fun_name() const {}

(5)對於類的成員函式,有時候必須指定其返回值為const型別,以使得其返回值不為“左值”。 const void fun_name() {}

83.  什麼是指標?談談你對指標的理解?

指標是一個變數,該變數專門存放記憶體地址;

指標變數的型別取決於其指向的資料型別,在所指資料型別前加*

指標變數的特點是它可以訪問所指向的記憶體。

84.  什麼是常指標,什麼是指向常變數的指標?

常指標的含義是該指標所指向的地址不能變,但該地址所指向的內容可以變化,使用常指標可以保證我們的指標不能指向其它的變數,

指向常變數的指標是指該指標的變數本身的地址可以變化,可以指向其它的變數,但是它所指的內容不可以被修改。指向長變數的指標定義,

85.  函式指標和指標函式的區別?

函式指標是指指向一個函式入口的指標;

指標函式是指函式的返回值是一個指標型別。

87.  簡述Debug版本和Release版本的區別?

Debug版本是除錯版本,Release版本是釋出給使用者的最終非除錯的版本,

88.  指標的幾種典型應用情況?

int *p[n];-----指標陣列,每個元素均為指向整型資料的指標。

int (*)p[n];------p為指向一維陣列的指標,這個一維陣列有n個整型資料。

int (*p)[n]; 陣列指標的正確定義方式。

// 這裡搞錯了吧!!! int (*p)[n]????????

int *p();----------函式返回回指標,指標指向返回的值。

int (*)p();------p為指向函式的指標。

// 下面 的是 行 列指標。

int main(int argc, char* argv[])

{

      int c[2][4];

      c[0][0] = 1;

      c[0][1] = 2;

      c[0][2] = 3;

      c[0][3] = 4;

      c[1][0] = 5;

      c[1][1] = 6;

      c[1][2] = 7;

      c[1][3] = 8;

      int (*p)[4] = c + 0; //  c + 0 為行指標!定義一個行指標 int (*p)[n],

//    int *p1 = c + 1; // 這裡會報錯。: cannot convert from 'int (*)[4]' to 'int *'

      int *pa = *c + 1; // *c+1 表示 列指標。!

      return 0;

}

// 關於 函式指標的概念。

void myfun( int a, int b)

{

      int c = 0;

      int d = 0;

      cout << "sdfsd" << endl;

}

void myfun1( int a, int b)

{

      int c = 0;

      int d = 0;

      cout << "sdfsd" << endl;

}

typedef void (*PMYFUN)( int a, int b );

PMYFUN iFxn;   // 用這種新的型別去定義一個 變數!

int main(int argc, char* argv[])

{

      iFxn = myfun; // 給該指標變數 賦值,表明他是指向那個函式。

      iFxn(2, 3);

      iFxn = myfun1;

      iFxn(32, 3); //  y用指標去掉具體的函式。

      return 0;

}

// 關於 函式指標的概念。

關於 函式指標的概念。 可以將這個 pThreadProc 理解為一個 新的型別,只不過該型別是一個指標。

  pThreadProc pfun1; // 用 pThreadProc 這種新的型別去定義的變數是一個指標。

      pfun1 = myfun; // 這句就是核心的程式碼,將指明呼叫的是那個函式。

current read

89.  static函式與普通函式有什麼區別?

static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝

90.  struct(結構) 和 union(聯合)的區別?

1. 結構和聯合都是由多個不同的資料型別成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 而結構的所有成員都存在(不同成員的存放地址不同)。

2. 對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構的不同成員賦值是互不影響的。

91.  class 和 struct 的區別?

struct 的成員預設是公有的,而類的成員預設是私有的。

92.  簡述列舉型別?

列舉方便一次定義一組常量,使用起來很方便;

93.  assert()的作用?

ASSERT()是一個除錯程式時經常使用的巨集,在程式執行時它計算括號內的表示式,如果表示式為FALSE (0), 程式將報告錯誤,並終止執行。如果表示式不為0,則繼續執行後面的語句。這個巨集通常用來判斷程式中是否出現了明顯非法的資料,如果出現了終止程式以免導致嚴重後果,同時也便於查詢錯誤。

94.  區域性變數和全域性變數是否可以同名?

能,區域性會遮蔽全域性。要用全域性變數,需要使用"::"(域運算子)。

95.  程式的區域性變數存在於(棧)中,全域性變數存在於(靜態區 )中,動態申請資料存在於( 堆)中。

96.  在什麼時候使用常引用?

如果既要利用引用提高程式的效率,又要保護傳遞給函式的資料不在函式中被改變,就應使用常引用。

97.  類的宣告和實現的分開的好處?

1.   起保護作用;

2.   提高編譯的效率。

98.  windows訊息系統由哪幾部分構成?

由一下3部分組成:

1.   訊息佇列:作業系統負責為程序維護一個訊息佇列,程式執行時不斷從該訊息佇列中獲取訊息、處理訊息;

2.   訊息迴圈:應用程式通過訊息迴圈不斷獲取訊息、處理訊息。

3.   訊息處理:訊息迴圈負責將訊息派發到相關的視窗上使用關聯的視窗過程函式進行處理。

99.  什麼是訊息對映?

訊息對映就是讓程式設計師指定MFC類(有訊息處理能力的類)處理某個訊息。然後由程式設計師完成對該處理函式的編寫,以實現訊息處理功能。

100. 什麼是UDP和TCP的區別是什麼?

TCP的全稱為傳輸控制協議。這種協議可以提供面向連線的、可靠的、點到點的通訊。

UDP全稱為使用者報文協議,它可以提供非連線的不可靠的點到多點的通訊。

用TCP還是UDP,那要看你的程式注重哪一個方面?可靠還是快速?

101. winsock建立連線的主要實現步驟?

答:

伺服器端:socket()建立套接字,繫結(bind)並監聽(listen),用accept()等待客戶端連線, accept()發現有客戶端連線,建立一個新的套接字,自身重新開始等待連線。該新產生的套接字使用send()和recv()寫讀資料,直至資料交換完畢,closesocket()關閉套接字。

客戶端:socket()建立套接字,連線(connect)伺服器,連線上後使用send()和recv(),在套接字上寫讀資料,直至資料交換完畢,closesocket()關閉套接字。

102. 程序間主要的通訊方式?

訊號量,管道,訊息,共享記憶體

103. 構成Win32 API 函式的三個動態連結庫是什麼?

答:核心庫,使用者介面管理庫,圖形裝置介面庫。

104. 建立一個視窗的步驟是?

答:填充一個視窗類結構->註冊這個視窗類->然後再建立視窗->顯示視窗->更新視窗。

105. 模態對話方塊和非模態對話方塊有什麼區別?

答:1.呼叫規則不同:前者是用DoModal()呼叫,後者通過屬性和ShowWindow()來顯示。

2.模態對話方塊在沒有關閉前使用者不能進行其他操作,而非模態對話方塊可以。

3.非模態對話方塊建立時必須編寫自己的共有建構函式,還要呼叫Create()函式。

106. 從EDIT框中取出資料給關聯的變數,已經把關聯的變數的資料顯示在EDIT框上的函式是什麼?

答: 取出 UpdateData(TRUE), 顯示 Updatedata(FALSE).

107. 簡單介紹GDI?

答;GDI是Graphics Device Interface 的縮寫,譯為:圖形裝置介面;是一個在Windows應用程式中執行與裝置無關的函式庫,這些函式在不同的輸出裝置上產生圖形以及文字輸出。

108. windows訊息分為幾類?並對各類做簡單描述。

1.視窗訊息:與視窗相關的訊息,除WM_COMMAND之外的所有以WM_開頭的訊息;

2.命令訊息;用於處理使用者請求,以WM_COMMAND表示的訊息;

3.控制元件通知訊息:統一由WM_NOTIFT表示,

4.使用者自定義訊息。

109. 如何自定義訊息?

使用WM_USER 和WM_APP兩個巨集來自定義訊息,

110. 簡述Visual C++ 、Win32 API和MFC之間的關係?

(1)  Visual C+是一個以C++程式設計語言為基礎的、整合的、視覺化的程式設計環境;

(2)  Win32 API是32位Windows操作系以C/C++形式提供的一組應用程式介面;

(3)  MFC是對Win32 API的封裝,簡化了開發過程。

111.怎樣消除多重繼承中的二義性?

1.成員限定符

2.虛基類

112什麼叫靜態關聯,什麼叫動態關聯

在多型中,如果程式在編譯階段就能確定實際執行動作,則稱靜態關聯,

如果等到程式執行才能確定叫動態關聯。

113多型的兩個必要條件(*****************************************)

1.一個基類的指標或引用指向一個派生類物件,

2.虛擬函式

114.什麼叫智慧指標?(*****************************************)

當一個類中,存在一個指向另一個類物件的指標時,對指標運算子進行過載,那麼當前類物件可以通過指標像呼叫自身成員一樣呼叫另一個類的成員。

115.什麼時候需要用虛解構函式?

當基類指標指向用new運算子生成的派生類物件時,delete基類指標時,派生類部分沒有釋放掉而造成釋放不徹底現象,需要虛解構函式。

116. MFC中,大部分類是從哪個類繼承而來?

      CObject

117.什麼是平衡二叉樹?

答:左右子樹都是平衡二叉樹,而且左右子樹的深度差值的約對值不大於1

118.語句for( ;1 ;)有什麼問題?它是什麼意思?

答:無限迴圈,和while(1)相同。

119.派生新類的過程要經歷三個步驟

1吸收基類成員

2.改造基類成員

3.新增新成員

121. TCP/IP 建立連線的過程

在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線。

第一次握手:建立連線時,客戶端傳送連線請求到伺服器,並進入SYN_SEND狀態,等待伺服器確認;

第二次握手:伺服器收到客戶端連線請求,向客戶端傳送允許連線應答,此時伺服器進入SYN_RECV狀態;

第三次握手:客戶端收到伺服器的允許連線應答,向伺服器傳送確認,客戶端和伺服器進入通訊狀態,完成三次握手

122 .memset ,memcpy 的區別

memset用來對一段記憶體空間全部設定為某個字元,一般用在對定義的字串進行初始化為''。

memcpy用來做記憶體拷貝,你可以拿它拷貝任何資料型別的物件,可以指定拷貝的資料長度;

123. 在C++ 程式中呼叫被 C 編譯器編譯後的函式,為什麼要加 extern “C”?(*****************************************)

      答:C++語言支援函式過載,C 語言不支援函式過載。函式被C++編譯後在庫中的名字

與C 語言的不同。假設某個函式的原型為: void foo(int x, int y);該函式被C 編譯器編譯後在庫中的名字為_foo , 而C++編譯器則會產生像_foo_int_int 之類的名字。C++提供了C 連線交換指定符號extern“C”來解決名字匹配問題。

124怎樣定義一個純虛擬函式?含有純虛擬函式的類稱為什麼?

在虛擬函式的後面加=0,含有虛擬函式的類稱為抽象類。

125.已知strcpy函式的原型是:

    char * strcpy(char * strDest,const char * strSrc);不呼叫庫函式,實現strcpy函式。

答案:

char *strcpy(char *strDest, const char *strSrc)

{

if ( strDest == NULL || strSrc == NULL)

return NULL ;

if ( strDest == strSrc)

return strDest ;

char *tempptr = strDest ; 

while( (*strDest++ = *strSrc++) != ‘\0’)

;

return tempptr ;

}

/// 下面的是我寫的!

char* strcpy(char *strDest,const char *strSrc)

{

      if( strSrc != NULL )

      {

char *tempptr = strDest; //  這步一定要!儲存沒有後移之前的字串的頭部指標

             while( *strSrc != '' )

             {

                    *strDest++ = *strSrc++;  // ++ 後, 2個指標分別都已經指向字串的尾部!

             }

             *strDest = '';

             return tempptr; //  返回一定要返回tempStr;

      }

      return NULL;

}

(下面這題沒有看!)

126.已知類String 的原型為:

class String

{

public:

String(const char *str = NULL); // 普通建構函式

String(const String &other); // 拷貝建構函式

~ String(void); // 解構函式

String & operate =(const String &other); // 賦值函式

private:

char *m_data; // 用於儲存字串

};

請編寫String 的上述4 個函式。

答案:

String::String(const char *str)

{

if ( str == NULL ) //strlen在引數為NULL時會拋異常才會有這步判斷

{

m_data = new char[1] ;

m_data[0] = '' ;

}

else

{

m_data = new char[strlen(str) + 1]; // 多分配一個。讓系統給你賦0

strcpy(m_data,str);

}

}

String::String(const String &other)

{

m_data = new char[strlen(other.m_data) + 1];

strcpy(m_data,other.m_data);

}

String & String::operator =(const String &other)

{

if ( this == &other)

return *this ;

delete []m_data;

m_data = new char[strlen(other.m_data) + 1];

strcpy(m_data,other.m_data);

return *this ;

}

String::~ String(void)

{

delete []m_data ;

}

// 下面的是我寫的!

///////////////////////////////////////////////////////////////////////////

class mystring

{

public:

      mystring( const char *pstr) // 相當於 string str("sdfsfsfsd");/ 普通建構函式

      {

             int templen = strlen(pstr)+1;

             int i = 0;

             m_cpData = new char[templen];

             while( *(pstr+i) != '' )

             {

                    *(m_cpData+i) = *(pstr+i) ;

                    i++;

             }

             *(m_cpData+i) = '';

      

      mystring( const mystring &str)

      {

      }

//    operator = ()

//private:

      char *m_cpData; // 用於儲存字串

};

int main(int argc, char* argv[])

{

      string str("sdfsdf");

      string str123 = "sdfsdfsd";

//    printf( "%sn", str123 ); // 估計是 printf() 不支援string

      cout << str123 << endl;

      cout << str << endl;

////   上面的程式碼是呼叫 string 實現的! 不知道預設的string的 str("dfdf")是前拷貝還是深拷貝??

////    下面我將呼叫 mystring 類 來實現。

      mystring mystr("using mystring!");

      printf( "mystrin is : %sn", mystr);

      cout << "=================" << endl;

      char *p = "sdfsfdsfsd";

      cout << strlen( p ) << endl;

      cout << sizeof(p) << endl;

      cout << "=================" << endl;

      char p1[10];

      cout << strlen( p1 ) << endl; //?15 其實這個15不是確定的,因為你沒有給p1 賦值。讀到''為止!

      cout << sizeof(p1) << endl;

      cout << "=================" << endl;

      char p3[20] = "123456";

      cout << strlen( p3 ) << endl; //6 你只給了6個值! 系統自動在後面加了一個 ''

      cout << sizeof(p3) << endl;

      cout << "=================" << endl;

      int p2[10];

//    cout << strlen( p2 ) << endl; // 錯了!函式原型size_t strlen( const char *string );

      cout << sizeof(p2) << endl;

//    cout << mystring << endl;

      return 0;

}

////////////////////////////////////////////////////////////////////////////////

label 星星星星星星星星星星星星星星

127.類成員函式的過載、覆蓋和隱藏區別

答案:

成員函式被過載的特徵:

(1)相同的範圍(在同一個類中);

(2)函式名字相同;

(3)引數不同;

(4)virtual 關鍵字可有可無。

覆蓋是指派生類函式覆蓋基類函式,特徵是:

(1)不同的範圍(分別位於派生類與基類);

(2)函式名字相同;

(3)引數相同;

(4)基類函式必須有virtual 關鍵字。

“隱藏”是指派生類的函式遮蔽了與其同名的基類函式,規則如下:

(1)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。

(2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)

128.如何打印出當前原始檔的檔名以及原始檔的當前行號?

答案:

cout << __FILE__ ;

cout<<__LINE__ ;

__FILE__和__LINE__是系統預定義巨集,這種巨集並不是在某個檔案中定義的,而是由編譯器定義的。

////////////////////////////////////////////////////////////////////////////////////////////////////////

129.檔案中有一組整數,要求排序後輸出到另一個檔案中

答案:

void Order(vector<int> &data) //起泡排序

{

int count = data.size() ;

int tag = false ;

for ( int i = 0 ; i < count ; i++)

{

for ( int j = 0 ; j < count - i - 1 ; j++)

{

if ( data[j] > data[j+1])

{

tag = true ;

int temp = data[j] ;

data[j] = data[j+1] ;

data[j+1] = temp ;

}

}

if ( !tag )

break ;

}

void Order(vector<int> &data) //起泡排序

{

    int count = data.size() ;

    int tag = false ;

    for ( int i = 0 ; i < count ; i++)

    {

        for ( int j = 0 ; j < count - i - 1 ; j++ )

        {

             if ( data[j] > data[j+1]) // 如果前一個大於後面的一個,交換。將小的提到陣列的前面

             {

                  tag = true ;

                  int temp = data[j] ;

                  data[j] = data[j+1] ;

                  data[j+1] = temp ;

            }

        }

        if ( !tag ) // 這裡表示前面一個本來就小於後一個。沒有執行交換。也不用交換。跳出,進行下一個比較。

             break ;

    }

}

}

void main( void )

{

vector<int>data;

ifstream in("c:\data.txt");

if ( !in)

{

cout<<"file error!";

exit(1);

}

int temp;

while (!in.eof())

{

in>>temp;

data.push_back(temp);

}

in.close();

Order(data);

ofstream out("c:\result.txt");

if ( !out)

{

cout<<"file error!";

exit(1);

}

for ( i = 0 ; i < data.size() ; i++)

out<<data[i]<<" ";

out.close();

}

////////////////////////////////////////////////////////////////////////////////////////////////////////

130.一個連結串列的結點結構

struct Node

{

int data ;

Node *next ;

};

typedef struct Node Node ;

已知連結串列的頭結點head,寫一個函式把這個連結串列逆序 ( Intel)

Node * ReverseList(Node *head) //連結串列逆序

{

    if ( head == NULL || head->next == NULL ) // 當連結串列沒有節點,或者只有一個節點。

        return head;

    Node *p1 = head ;