C++中有無數的坑,但畢竟……
今天就踩到了,也算是基本問題了,記錄一下,順便以后可以考考自己。你也可以猜猜答案,大牛繞行。
0x1 先看這個:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 Bpp* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:
~Bpp
~App
請按任意鍵繼續. . .
0x02 : 再來 ,改了第32行
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 App* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:
~App
請按任意鍵繼續. . .
0x03 下一個 改動 7 line
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 virtual ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 App* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:
~Bpp ~App 請按任意鍵繼續. . .
0x04 next 改動 line 20
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 virtual ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 virtual ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 App* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果和 0x03一樣:
~Bpp ~App 請按任意鍵繼續. . .
0x05 接着 再在第7 行中 去掉 virtual
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 virtual ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 App* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:
在33行,程序報錯,崩潰。
0x6 改動 32行:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 virtual ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 void* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:執行成功。
請按任意鍵繼續. . .
0x07 把所有 virtual 去掉
#include <stdio.h> #include <stdlib.h> class App { public: ~App() { printf("\n~App\n"); } void output() { printf("A"); } }; class Bpp : public App { public: ~Bpp() { printf("\n~Bpp\n"); } void output() { printf("B"); } }; int main(char args[]) { void* b = new Bpp(); delete b; system("pause"); return 0; }
結果:
請按任意鍵繼續. . .
0x08 加上所有 virtual :
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 virtual ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 virtual ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 void* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果:
請按任意鍵繼續. . .
0x09 最后:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 class App 5 { 6 public: 7 ~App() 8 { 9 printf("\n~App\n"); 10 } 11 void output() 12 { 13 printf("A"); 14 } 15 }; 16 17 class Bpp : public App 18 { 19 public: 20 virtual ~Bpp() 21 { 22 printf("\n~Bpp\n"); 23 } 24 void output() 25 { 26 printf("B"); 27 } 28 }; 29 30 int main(char args[]) 31 { 32 Bpp* b = new Bpp(); 33 delete b; 34 35 system("pause"); 36 return 0; 37 }
結果,可以猜猜:

1 ~Bpp 2 3 ~App 4 請按任意鍵繼續. . .
結語:
1. 通常應該給基類提供一個虛析構函數,即使它不需要析構函數 —— 《C++ Primer Plus (第6版)中文版》, 505頁
2. 如果一個類帶有任何 virtual 函數,這個類就應該擁有 virtual 析構函數 —— 《Effective C++ 中文版,第三版》,條款07:為多態基類聲明 virtual 析構函數,44頁
3. 如果一個類被當作基類(也就是說這個類需要被其他類繼承),那這個類的析構函數就要加上 virual 關鍵字!