为啥继承时基类的析构一般声明为虚函数
来源:互联网 发布:sql删除表中全部数据 编辑:程序博客网 时间:2024/05/21 22:50
1、为啥继承时基类的析构函数声明为虚函数?
文字描述太抽象了,直接用代码给出答案。
(1)第一段代码:
#include<iostream>using namespace std ;class Base{public:Base(){cout << "基类的构造函数被调用了" << endl;} ~Base(){cout << "基类的析构函数被执行了" <<endl;}};class Derived :public Base{public:Derived(char *str = ""){if (str == NULL){_Dstr = new char[1];*_Dstr = '\0';}else{_Dstr = new char [strlen(str) + 1];strcpy(_Dstr, str);}cout << "派生类的构造函数被调用了" << endl;}~Derived(){if (_Dstr != NULL){delete [] _Dstr;_Dstr = NULL;}cout << "派生类的析构函数被执行了" <<endl;}private:char *_Dstr;};void test(){Base B1;Base & b = B1; //基类的引用或指针指向基类对象。}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
(2)第二段代码
#include<iostream>using namespace std ;class Base{public:Base(){cout << "基类的构造函数被调用了" << endl;} ~Base(){cout << "基类的析构函数被执行了" <<endl;}};class Derived :public Base{public:Derived(char *str = ""){if (str == NULL){_Dstr = new char[1];*_Dstr = '\0';}else{_Dstr = new char [strlen(str) + 1];strcpy(_Dstr, str);}cout << "派生类的构造函数被调用了" << endl;}~Derived(){if (_Dstr != NULL){delete [] _Dstr;_Dstr = NULL;}cout << "派生类的析构函数被执行了" <<endl;}private:char *_Dstr;};void test(){Base * b = new Derived("str"); //基类的引用或指针指向派生类对象。delete b;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
//分析答案发现析构时,只调用了基类的析构函数,没有调用派生类的析构函数,导致派生类内存泄露,
(3)第三段代码
#include<iostream>using namespace std ;class Base{public:Base(){cout << "基类的构造函数被调用了" << endl;} virtual ~Base() //将基类的析构函数声明为虚函数。 {cout << "基类的析构函数被执行了" <<endl;}};class Derived :public Base{public:Derived(char *str = ""){if (str == NULL){_Dstr = new char[1];*_Dstr = '\0';}else{_Dstr = new char [strlen(str) + 1];strcpy(_Dstr, str);}cout << "派生类的构造函数被调用了" << endl;}~Derived(){if (_Dstr != NULL){delete [] _Dstr;_Dstr = NULL;}cout << "派生类的析构函数被执行了" <<endl;}private:char *_Dstr;};void test(){Base * b = new Derived("str"); //基类的引用或指针指向派生类对象。delete b;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
//答案分析:析构时,先调用了派生类的析构函数,再调用基类的析构函数,不存在内存泄露。反过来看源代码只是发现只是将基类的析构函数声明为虚函数。
结论: 继承时,如果派生类有资源需要自己手动释放,最好将基类的析构函数声明为虚函数,这样我们可以通过基类的指针或引用去释放子类的资源。防止内存泄露。
2.当我们想要继承一个抽象类的时候,但是还不能确定抽象类的那些成员是纯虚函数,我们可以将抽象类的析构函数声明为纯虚函数。
(1)第一段代码
#include<iostream>using namespace std ;class Abstract{public:virtual ~Abstract() = 0;};class Derived: public Abstract{public:Derived(){cout << "派生类的构造函数被执行了" <<endl;}~Derived(){cout << "派生类的析构函数被执行了" << endl;}};void test(){Derived d;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
如果我们单纯的直接这么写,我们发现编译器报错,报下列的错误:
抽象类的析构函数.obj : error LNK2019: 无法解析的外部符号 "public: virtual __thiscall Abstract::~Abstract(void)" (??1Abstract@@UAE@XZ),该符号在函数 __unwindfunclet$??0Derived@@QAE@XZ
通过分析:我们发现定义派生类对象时,会先调用抽象类的构造函数,抽象类的构造函数没有显示的给出,编译器合成一个默认的构造函数,再调用派生类的构造函数,析构时,先调用派生类的析构函数,最后调用抽象类的析构函数,但是抽象类的析构函数已经显示的声明了,因此会调用程序员自己写的,但是这个析构函数没有函数体,所以编译器报错,说无法解析的外部符号,
解决方案:给抽象类的析构函数定义。看下面的代码:
(2)第二段代码:
#include<iostream>using namespace std ;class Abstract{public:virtual ~Abstract() = 0;}; Abstract:: ~Abstract(){cout << "抽象类的析构函数被执行了" <<endl;};class Derived: public Abstract{public:Derived(){cout << "派生类的构造函数被执行了" <<endl;}~Derived(){cout << "派生类的析构函数被执行了" << endl;}};void test(){Derived d;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
- 为啥继承时基类的析构一般声明为虚函数
- 将 析构函数 声明为 虚函数 的必要性
- 析构函数声明为虚函数的情况
- 为什么要将基类的析构函数声明为虚函数
- 析构函数声明为虚函数
- 析构函数声明为虚函数
- 为什么构造函数不能声明为虚函数,析构函数可以声明为虚函数
- 构造函数不能声明为虚函数,析构函数可以声明为虚函数
- 析构函数为啥是虚函数
- C++ 析构函数 为何一般定义为虚函数
- C++ 析构函数 为何一般定义为虚函数
- 不能声明为虚函数的函数
- 不能声明为虚函数的函数
- 不能声明为虚函数的函数:
- 不能声明为虚函数的函数
- 构造函数、析构函数是否要声明为虚函数的问题
- 构造函数、析构函数是否要声明为虚函数的问题(网络转载)
- 构造函数、析构函数是否要声明为虚函数的问题
- Image classification with deep learning常用模型
- lua的Table.getn在MAC上使用问题
- <1>CComboBoxEx添加图像CImageList无法正常显示
- LayoutInflater是如何“移花接木”-上篇
- c++中必须在类初始化列表中初始化的几种情况摘要
- 为啥继承时基类的析构一般声明为虚函数
- Highways
- 深度探索c++对象模型之带有constructor类数组的new语义学
- 数据通信与计算机网络
- OpenGL如何显示透明PNG
- 数据结构实验之查找一:二叉排序树
- Tyvj 1363 火车进出栈问题 (高精度+卡特兰数+组合数学)
- Unity使用VS开发编码格式的问题
- mini2440 系统安装