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語言是面向過...