C++知識記錄1

3.malloc和new

1.malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。但它們都可用於申請動態內存和釋放內存。

2.對於非內部數據類型的對象而言,用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free,因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,和一個能完成清理與釋放內存工作的運算符delete。

3.new可以認爲是malloc加構造函數的執行。new出來的指針是直接帶類型信息的。而malloc返回的都是void*指針。new delete在實現上其實調用了malloc,free函數。

4.new 建立的是一個對象;malloc分配的是一塊內存。

4.虛函數實現機制,虛繼承在sizeof中有沒有影響,構造函數能否爲虛函數,與純虛函數

虛函數表:類的虛函數表是一塊連續的內存,每個內存單元中記錄一個JMP指令的地址。

編譯器會爲每個有虛函數的類創建一個虛函數表,該虛函數表將被該類的所有對象共享。類的每個虛函數佔據虛函數表中的一塊。如果類中有N個虛函數,那麼其虛函數表將有N*4字節的大小。

在有虛函數的類的實例中分配了指向這個表的指針的內存,所以,當用父類的指針來操作一個子類的時候,這張虛函數表就顯得尤爲重要了,它就像一個地圖一樣,指明瞭實際所應該調用的函數。

編譯器應該是保證虛函數表的指針存在於對象實例中最前面的位置(這是爲了保證取到虛函數表的有最高的性能——如果有多層繼承或是多重繼承的情況下)。 這意味着可以通過對象實例的地址得到這張虛函數表,然後就可以遍歷其中函數指針,並調用相應的函數。

->有虛函數或虛繼承的類實例化後的對象大小至少爲4字節(確切的說是一個指針的字節數;說至少是因爲還要加上其他非靜態數據成員,還要考慮對齊問題);沒有虛函數和虛繼承的類實例化後的對象大小至少爲1字節(沒有非靜態數據成員的情況下也要有1個字節來記錄它的地址)。

有純虛函數的類爲抽象類,不能定義抽象類的對象,它的子類要麼實現它所有的純虛函數變爲一個普通類,要麼還是一個抽象類。

特別的

(1)當存在類繼承並且析構函數中有必須要進行的操作時(如需要釋放某些資源,或執行特定的函數)析構函數需要是虛函數,否則若使用父類指針指向子類對象,在delete時只會調用父類的析構函數,而不能調用子類的析構函數,從而造成內存泄露或達不到預期結果;

(2)內聯函數不能爲虛函數:內聯函數需要在編譯階段展開,而虛函數是運行時動態綁定的,編譯時無法展開;

(3)構造函數不能爲虛函數:構造函數在進行調用時還不存在父類和子類的概念,父類只會調用父類的構造函數,子類調用子類的,因此不存在動態綁定的概念;但是構造函數中可以調用虛函數,不過並沒有動態效果,只會調用本類中的對應函數;

(4)靜態成員函數不能爲虛函數:靜態成員函數是以類爲單位的函數,與具體對象無關,虛函數是與對象動態綁定的。

更多關於虛函數的細節,請移步博文:關於C++虛函數表的那些事兒http://www.cnblogs.com/webary/p/4731457.html

11.extern “C”的作用

extern "C"實現C++與C及其它語言的混合編程,是用在C和C++之間的橋樑。之所以需要這個橋樑是因爲C編譯器編譯函數時不帶函數的類型信息,只包含函數符號名字;而C++編譯器爲了實現函數重載,編譯時會帶上函數的類型信息,如他把上面的a函數可能編譯成_a_float這樣的符號爲了實現重載。

extern "C"的慣用法:

在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設爲cExample.h)時,需進行下列處理:

extern “C”{

#include “cExample.h”

}

而在C語言的頭文件中,對其外部函數只能指定爲extern類型,C語言中不支持extern "C"聲明,在.c文件中包含了extern "C"時會出現編譯語法錯誤。

extern本身作爲關鍵字修飾變量(函數)時聲明該變量(函數)是外部變量(函數),通常全局變量在頭文件中用這種方式聲明,在對應源文件中定義,來防止重定義的錯誤。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章