new 和 malloc 的區別是什麼?
delete 和 free 的區別是什麼?ios
new 關鍵字和 malloc 函數的區別編程
- new 關鍵字是 C++ 的一部分
- malloc 是 C 庫提供的函數
- new 以具體類型爲單位進行內存分配
- malloc 以字節爲單位進行內存分配
- new 在申請內存空間時可進行初始化
- malloc 僅根據須要申請定量的內存空間
#include <iostream> #include <cstdlib> using namespace std; class Test { private: int* mp; public: Test() { cout << "Test::Test()" << endl; mp = new int(100); } ~Test() { delete mp; cout << "~Test::Test()" << endl; } }; int main() { Test* pn = new Test; Test* pm = (Test*)malloc(sizeof(Test)); delete pn; free (pm); return 0; }
輸出: Test::Test() ~Test::Test() 分析: new Test; ==> 在堆上建立一個對象,構造函數被調用 (Test*)malloc(sizeof(Test)); ==> 在堆上申請 sizeof(Test) 大小內存,構造函數未被調用,對象未正常建立 delete pn; ==> 銷燬對象, 歸還內存,析構函數被調用 free(pm); ==> 僅歸還內存,析構函數未被調用
當 delete 與 free 混用,會發生什麼呢?安全
delete --> free :函數
int main() { Test* pn = new Test; free (pn); // 注意這裏! return 0; }
輸出: Test::Test() 分析: free 能夠釋放 new 申請的堆空間,但析構函數未被調用,對象未正常銷燬(實例中,致使系統資源泄漏!!)
free --> delete :spa
int main() { Test* pm = (Test*)malloc(sizeof(Test)); delete pm; // 注意這裏! return 0; }
輸出: ~Test::Test() 分析: delete 能夠釋放 malloc 申請的堆空間,不合法對象的析構函數被調用!運行結果將是不肯定的!(示例中,將delete一個野指針指向的內存空間)
結論: C++ 中杜絕 malloc、 free 的使用設計
new 和 malloc 的區別指針
- new 在全部 C++ 編譯器中都被支持
- malloc 在某些系統開發中不能調用
- new 可以觸發構造函數的調用
- malloc 僅分配須要的內存空間
- 對象的建立只能使用 new
- malloc 不適合面向對象開發
delete 和 free 的區別code
- delete 在全部 C++ 編譯器中都被支持
- free 在某些系統開發中不能調用
- delete 可以觸發析構函數的調用
- free 僅歸還以前分配的內存空間
- 對象的銷燬只能使用 delete
- free 不適合面向對象開發
構造函數是否能夠成爲虛函數?
析構函數是否能夠成爲虛函數?對象
構造函數不可能成爲虛函數繼承
- 在構造函數執行結束後,虛函數表指針纔會被正確的初始化
析構函數能夠成爲虛函數
- 析構函數在對象銷燬以前被調用,意味着虛函數表指針仍然正確的指向虛函數表
- 建議在設計類時將析構函數聲明爲虛函數
test_1.cpp
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } virtual void func() { cout << "Base::func()" << endl; } ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; } virtual void func() { cout << "Derived::func()" << endl; } ~Derived() { cout << "~Derived()" << endl; } }; int main() { Base* p = new Derived(); // 注意這裏! // ... delete p; return 0; }
輸出: Base() Derived() ~Base() 分析: 爲何 子類 的析構函數沒有被調用呢? Base* p = new Derived(); ==> 由於賦值兼容性,編譯經過。 delete p; ==> 編譯器考慮安全性,根據指針類型進行對象銷燬
析構函數聲明爲虛函數的意義 1:test_2.cpp
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } virtual void func() { cout << "Base::func()" << endl; } virtual ~Base() // 注意這裏! { cout << "~Base()" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; } virtual void func() { cout << "Derived::func()" << endl; } ~Derived() { cout << "~Derived()" << endl; } }; int main() { Base* p = new Derived(); // ... delete p; return 0; }
輸出: Base() Derived() ~Derived() ~Base() 分析: 當析構函數爲虛函數時, delete p; 將根據 p 指向的實際對象決定如何調用析構函數。
析構函數發生多態行爲,保證系統資源儘量獲得釋放!
當聲明構造函數爲虛函數時,g++ 報錯: virtual Base() { } error: constructors cannot be declared virtual
構造函數中是否能夠發生多態?
析構函數中是否能夠發生多態?
構造函數中不可能發生多態行爲
- 在構造函數執行時,虛函數表指針未正確初始化
析構函數中不可能發生多態行爲
- 在析構函數執行時,虛函數表指針已經被銷燬
構造函數和析構函數中不能發生多態行爲, 只調用當前類中定義的函數版本!
繼承中如何正確的使用強制類型轉換?
- dynamic_cast 是與繼承相關的類型轉換關鍵字
- dynamic_cast 要求相關的類中必須有虛函數
用於直接或間接繼承關係的指針(引用)之間
指針:
- 轉換成功: 獲得目標類型指針
- 轉換失敗: 獲得一個空指針
引用:
- 轉換成功: 獲得目標類型引用
- 轉換失敗: 獲得一個異常操做信息
- 編譯器會檢查 dynamic_cast 的使用是否正確
- 類型轉換的結果只可能在運行階段才能獲得
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } virtual ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { }; int main() { Base* p = new Base(); // 注意這裏! Derived* pd = dynamic_cast<Derived*>(p); // 注意這裏! if( pd != NULL ) { cout << "pd = " << pd << endl; } else { cout << "Cast error!" << endl; } delete p; return 0; }
輸出: Base() Cast error! ~Base()
析構函數聲明爲虛函數的意義 2 :
析構函數被聲明爲虛函數,保證 dynamic_cast 關鍵字能夠被支持,而無需單獨刻意定義其它虛成員函數
- new / delete 會觸發構造函數或者析構函數
- 構造函數不能成爲虛函數
- 析構函數能夠成爲虛函數(推薦析構函數成爲虛函數)
- 構造函數和析構函數中都沒法產生多態行爲
- dynamic_cast 是與繼承相關的專用轉換關鍵字
以上內容參考狄泰軟件學院系列課程,請你們保護原創!