C和C 的區別和聯絡(擴充套件知識)

2021-07-28 19:45:41 字數 3981 閱讀 3795

2017/3/17 複習整理:c/c++區別與聯絡;

關於c和c++的區別是面試中經常會被問到的問題,本著即將面試的心態,進行知識整理,並對小知識點進行擴充套件;

c/c++的聯絡:

c/c++區別:

小知識點補充擴充套件

free();而new開闢物件陣列用的是new[size] ,釋放的的時候是 delete

(儘管內建型別可能不會引起問題,但是自定義型別的話,delete需要知道有

多少個物件,而這個計數就被放在這塊空間的頭部);

返回值問題,malloc開闢成功返回void*,需要強轉,失敗返回null,new

成功返回物件指標,失敗丟擲異常(這就可能會提到c++的new_handler機

制),雖然為了最大程度的相容c,c++的new也支援失敗返回null,但是一般不

被使用,大家可以了解一下;

是否呼叫構造和析構,這點應該放在前面,new和free不但負責開闢空間,

還會呼叫物件的建構函式和析構函式;最好了解一下new的三種表達形式(new運

算符,operator new(); placement new();)還有定位new表示式的

使用;是否可以相互呼叫,new的實現可以用malloc,malloc的實現不可以使用

new;

是否可以被過載,我們可以過載自己的operator new/delete,但是不可

以過載new/delete/malloc/free;

malloc開闢 的記憶體如果太小,想要換一塊大一點的,可以呼叫relloc實

現,但是new沒有直觀的方法來改變;

第十點其實前面已經提到,當new中的底層實現如果獲取不到更多的記憶體,

會觸發new_handler機制,留有乙個set_new_handler控制代碼,看看使用者是否設

置了這個控制代碼,如果設定了就去執行,控制代碼的目的是看看能不能嘗試著從操作系

統釋放點記憶體,找點記憶體,如果實在不行就丟擲bad_alloc異常;而malloc就

沒有這種嘗試了;——-

擴充套件_3 常見關鍵字的作用

**1.static 關鍵字:**

修飾全域性變數時,會將變數的鏈結屬性變為內部鏈結屬性,並且變數

的儲存位置變為全域性靜態區;

修飾 區域性變數,改變區域性變數的儲存位置為靜態儲存區,改變區域性變

量的生命週期為整個程式開始到結束;

修飾類的成員變數和函式:屬於類而不屬於物件,屬於所有例項類;

**2.const關鍵字**

修飾全域性變數:c/c++略有不同,在上文已經提到,即c++的const修

飾的全域性變數可以作為屬組的初始化的大小,而c不可以;同時變數的

值不能被修改;c++利用const的這一屬性,代替c中的define進行

全域性常量的定義;擴充套件_4會就 define,const,inline進行對比

和分析;

修飾區域性變數:代表區域性變數的值不能被修改;

修飾指標:這個是經常問道的,我舉的例子可能不全面,但是是比較

常見的例子:

cons t int *p; //修飾的是p所指向的內容不能被改變,p可

以;int const *p; //和上面是一樣的;

int* const p; //修飾的p指標不能改變;

修飾類的成員變數:必須在初始化列表初始化,除此之外,必須在初

始化列表初始化的還有,引用型別的資料成員,沒有預設建構函式的

物件成員,如果存在繼承關係,如果父類沒有預設的建構函式,則也

必須在初始化列表中被初始化,初始化列表對資料成員的初始化順序

是按照資料成員的宣告順序嚴格執行的;

修飾類的成員函式:一般放在成員函式的最後面,修飾的是類的成員

函式中的隱藏引數this指標,代表不可以通過this指標修改類的資料

成員,宣告形式例如:

base::void fun() const;

關於const還有乙個問題就是傳參和賦值的問題,一般來說,const

修飾的變數是安全的,沒有const修飾的變數是不安全的,一般在傳

參的時候,非const修飾的的變數可以傳給const修飾的,而const

修飾的不可以傳給非const修飾的形參,這就相當於把安全的東西交

給了不安全的人;而賦值的話更不用說了,const修飾的不可以傳給

沒有const修飾的變數;

**3.volatile**

volatile一般修飾變數,而它存在的原因是因為,我們的程式在進行

編譯的時候,編譯器會進行一系列的優化,比如,某個變數被修飾為

const的,編譯器就認為,這個值是唯讀的,就會在暫存器中儲存這

個變數的值,每次需要的時候從暫存器直接讀取,但是有時候,我們

可能會在不經意間修改了這個變數,比如說我們去了這個變數的地

址,然後強行改變這個變數在記憶體中的值,那麼編譯器並不知道,讀

取還是從暫存器中讀取,這就造成了結果的不匹配,而volatile宣告

的變數就會告訴編譯器,這個變數隨時會改變,需要每次都從內從中

讀取,就是不需要優化,從而避免了這個問題,其實,volatile應用

更多的場景是多執行緒對共享資源的訪問的時候,避免編譯器的優化,

而造成多執行緒之間的通訊不匹配!;

explicit關鍵字

首先需要了解什麼是隱式轉換,即在你沒有進行顯示的強轉的情況

下,賦值運算子左右兩個型別不一致的物件進行了型別轉換;或者

函式傳參的時候進行了型別轉換; 而explicit關鍵字存在的目的就是

禁止類的建構函式進行隱式的型別轉換,常見的就是string類的物件

就可以隱式型別轉換,比如:

strig  s = "hello world";

因為string 有乙個單參的char*建構函式,所有可以用hello w

orld構造乙個string物件,然後呼叫string 類的拷貝建構函式;

有時候我們並不希望這種不是我們預期的情況發生,所以,我們可以

在類的建構函式之前+explicit關鍵字。禁止隱式轉換;

---希望讀者提建議繼續補充!(補充文章中講到的所有內容的不足之處)

擴充套件_4 define /const/inline 對比和分析

define作用於程式的預處理階段,而預處理階段做的主要工作為下面幾個

方面:巨集替換,去注釋以及條件編譯; define起作用的地方就在巨集替換階

段,只是單純的將巨集替換為**,例如:

#define add(a+b) a+b
下面這段**用到了這個巨集:

int main()

從上面這個例子我們可以看出define的缺點很明顯,首先,define只 是單純的**替換,不會進行型別的檢查,再者,我們上面的巨集定義 也很粗糙,嚴格點應該定義為: #define add(a,b) (a)+(b) c++中一般建議使用const,列舉定義常量,這樣就會有型別檢查; 而巨集定義也可以定義出和函式一樣的功能: #define swap(type,a,b) 其實就算這樣寫,也還是存在上面提到的問題,並且這樣還不能進行調 試,因為巨集在預處理階段就替換了;

於是c++中又提供了乙個inline內聯關鍵字 ,可以實現和define相同的

功能,並且支援型別檢查和除錯,一般宣告在函式的定義的前面,不過, inline只是對編譯器的一種建議,一般如果**在3-5行左右,且沒有復 雜的邏輯結構,例如迴圈啊,遞迴啊,就可以宣告為inline,inline也

是在函式呼叫的地方替換**塊,所以**太長的話,容易造成程式膨脹,那麼inline為什麼可以支援除錯呢?

其實支援除錯也只是在dbug模式下,inline真正起作用是在release模

式,正好和assert相反;

C和C 的區別和聯絡

關於c和c 的區別是面試中經常會被問到的問題,本著即將面試的心態,進行知識整理,並對小知識點進行擴充套件 c c 的聯絡 c c 區別 小知識點補充擴充套件 free 而new開闢物件陣列用的是new size 釋放的的時候是 delete 儘管內建型別可能不會引起問題,但是自定義型別的話,dele...

C和C 的聯絡和區別

c和c 的聯絡 c 是c的超集,它相容大部分的c的語法的結構。c和c 的區別 c是面向過程的語言,而c 是物件導向的程式語言 物件導向的思想 c和c 動態記憶體管理不一樣,c語言中用malloc和free函式,c 中除此之外還有new和delete關鍵字。關於malloc free和new dele...

C和C 的聯絡與區別

面向過程的思路 分析解決問題所需的步驟,用函式把這些步驟依次實現。物件導向的思路 把構成問題的事務分解為各個物件,建立物件的目的,不是完成乙個步驟,而是描述某個事務在解決整個問題步驟中的行為。從上述描述可以看出,其實物件導向和面向過程是兩種思考解決問題的方式,其差異主要在於思考的角度。c語言是面向過...