【日常】C++ 的那些“坑” —— delete 与 析构函数 与 virtual 的 9 个小例子
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 关键字!