先看代碼:ios
1 #include<iostream>
2 using namespace std; 3
4 class Parent { 5 public: 6 Parent() :a(100), b(200), c(300) 7 { 8
9 p = new char[10]; 10 //strcpy(p, "abc");
11 cout << "parent 無參構造。。。\n"; 12 } 13 Parent(int test) :a(1000), b(2000), c(3000) 14 { 15 p = new char[10]; 16 //strcpy(p, "abc");
17 cout << "parent 有參構造。。。\n"; 18 } 19 ~Parent() 20 { 21 delete[] p; 22 cout << "Parent 析構。。。\n"; 23 } 24 int a; 25 int b; 26 int c; 27 char *p; 28 void p_print() 29 { 30 cout << "a b c is" << a << " " << b << " " << c << endl; 31 } 32
33 }; 34 class Child1 : public Parent 35 { 36 public: 37 Child1() :Parent(1),a(10), b(0), c(0) 38 { 39 p = new char[10]; 40 // strcpy(p, "abc");
41 cout << "child1 構造\n"; 42 } 43 ~Child1() 44 { 45 delete[] p; 46 cout << "child1 析構,,,\n"; 47 } 48 void c1_print() 49 { 50 cout << "a b c is" << a << " " << b << " " << c << endl; 51 } 52
53 int a; 54 int b; 55 int c; 56 char *p; 57 }; 58 class Child2 : public Child1 59 { 60 public: 61 Child2() :Child1(), b(2), c(3) 62 { 63 p = new char[10]; 64 //strcpy(p, "abc");
65 cout << "child2 構造\n"; 66 } 67 ~Child2() 68 { 69 delete[] p; 70 cout << "child2 析構,,,\n"; 71 } 72 void c2_print() 73 { 74 cout << "a b c is" << Parent::a << " " << b << " " << c << endl; 75 } 76 //int a;
77 int b; 78 int c; 79 char *p; 80 }; 81 /*
82 class Child3 : public Child1, public Child2 83 { 84 public: 85 Child3() : Child1(), Child2(), b(20), c(30) { cout << "child 構造\n"; } 86 ~Child3() 87 { 88 cout << "child 析構,,,\n"; 89 } 90 void c3_print() 91 { 92 cout << "a b c is" << a << " " << b << " " << c << endl; 93 } 94 //int a; 95 int b; 96 int c; 97 }; 98 */
99 void play() 100 { 101 Child2* c2 = new Child2; 102 delete c2; 103 } 104 int main() 105 { 106 //Child2* c2 = new Child2;
107 play(); 108 return 0; 109 }
這樣是沒問題的(c++編譯器會以構造相反的順序執行析構函數),可是,在不少時候,咱們不能在調用函數末尾就delete掉這個內存,還須要和後續交互。好比做爲函數參數,爲了實現多態,咱們函數參數是父類的指針,因此更常見和通常的設計思惟是更改paly和main函數以下:c++
1 void play(Parent* p) 2 { 3 delete p; 4 } 5 int main() 6 { 7 Child2* c2 = new Child2; 8 play(c2); 9 return 0; 10 }
運行結果顯示內存泄漏了,只析構了父類;因此咱們有那麼一種需求,要想和多態的效果同樣,傳什麼指針去,自動析構應該析構的東西,更改代碼,實現虛析構函數。函數
只用更改基類的析構函數,加上virtual關鍵字:spa
1 virtual ~Parent() 2 { 3 delete[] p; 4 cout << "Parent 析構。。。\n"; 5 }
這樣就沒有內存泄漏了。設計
知識簡要:指針
若是基類的析構函數不是虛函數,則delete一個指向派生類對象的基類指針將產生未定義的行爲。以前咱們介紹過一個準則,若是一個類須要析構函數,那麼它一樣須要拷貝和賦值操做。基類的析構函數並不遵循上述準則,它是一個重要的例外。code