爲上週題目中的 Fruit和Apple 添加 構造函數與 析構函數, 並在構造函數與析構函數中打印控制檯信息,觀察構造和析枸調用過程。而後爲Apple類重載::operator new和 ::operator delete,在控制檯打印信息,並觀察調用結果。
由於題目比較簡單,很少說直接上代碼ios
#include<iostream> using namespace std; class Fruit { int no; double weight; char key; public: Fruit() { cout << "creat Fruit" << endl; } virtual~Fruit() { cout << "delete Fruit" << endl; } void print() { } virtual void process() { } }; class Apple : public Fruit { int size; char type; public: Apple() { cout << "creat Apple" << endl; } void* operator new(size_t siz) { Apple* p = (Apple*)malloc(siz); cout << "new object" << endl; return p; } void* operator new[](size_t siz) { Apple* p = (Apple*)malloc(siz); cout << "new OBJECT" << endl; return p; } void operator delete (void* p, size_t siz) { cout << "delete object" << endl; cout << "size=" << siz << endl; free(p); } void operator delete[](void* p, size_t siz) { cout << "delete OBJECT" << endl; cout << "size=" << siz << endl; free(p); } ~Apple() { cout << "delete Apple" << endl; } void save() { } virtual void process() { } }; int main() { /*Fruit s1; Apple a1; Apple* a1=new Apple; delete a1; Apple* a2 = new Apple[5]; delete[] a2; Fruit *s1 = new Apple; delete s1;*/ return 0; }
當使用stack內存建立對象時,函數
Fruit s1; Apple a1;
對構造函數和析構函數執行結果如圖:測試
可見對象是根據其在代碼中的聲明順序建立的。而且在建立子類對象時,先調用父類的構造函數,再調用子類的構造函數,在刪除對象時,先調用子類的析構函數,再調用父類的析構函數。當聲明順序爲ui
Apple a1; Fruit s1;
運行結果以下:spa
能夠看出,對象的存儲在棧中遵循其先進後出原則,最早定義的最後被析構。
隨後咱們對new 和delete 操做符進行重載指針
Apple* a1=new Apple; delete a1;
運行結果以下:code
可見對象的構造和析構遵循以下順序:
構造時,先申請內存 再調用構造函數
析構時,先調用析構函數,再刪除內存。
若是對象有父類,則構造函數和析構函數的調用順序遵循上面的結論。
operater new[]和operator delete[]對象
Apple* a2 = new Apple[5]; delete[] a2;
對構造函數和析構函數的調用方式基本和上述相同惟一不一樣的是內存的申請和釋放只有一次,隨後屢次執行構造和析構。
運行結果以下:ip
最後再測試一下父類指針管理的對象:內存
Fruit *s1 = new Apple; delete s1;
運行結果:
因爲在聲明時,基類的析構函數已經聲明爲虛函數,所以在析構時對對象的動態綁定,雖然傳入的是父類的指針,可是在實際調用的是子類的析構函數。