多态使用时,如果子类中有属性开辟到堆区,那么父类指针在调用时无法调用到子类析构代码

    解决方式:将父类中的虚构函数改为虚析构函数或纯虚析构函数

    虚析构和纯虚析构共性:
    1:都可以解决父类指针释放子类指针现象
    2:都需要具体的函数实现

    虚析构和纯虚析构的区别:
    乳沟是纯虚析构函数则该类时抽象类 无法实例化对象

    虚析构语法;
    virtual ~类名()
    {
    }

    纯虚析构语法
    virtual ~类名()=0;

    类名::类名(){ }

    示例:

    1. #include<iostream>
    2. using namespace std;
    3. class Animal
    4. {
    5. public:
    6. Animal()
    7. {
    8. cout<<"Animal构造函数的调用"<<endl;
    9. }
    10. //利用虚析构或纯虚析构可以解决 父类指针释放子类对象不干净问题。
    11. //虚析构函数
    12. // virtual ~Animal()
    13. // {
    14. // cout<<"虚析构函数的调用"<<endl;
    15. // }
    16. //纯虚析构函数
    17. //既需要声明也需要有实现
    18. //有了纯虚析构之后, 这个类也属于抽象类,无法实例化对象
    19. virtual ~Animal()=0;
    20. //在类内初始化的是虚函数类外初始化的是纯虚函数(其他的同理)
    21. //纯虚函数
    22. virtual void speak()=0;
    23. //纯虚函数没有必要初始化
    24. };
    25. Animal::~Animal()
    26. {
    27. cout<<"纯虚析构函数的调用"<<endl;
    28. }
    29. class Cat:public Animal
    30. {
    31. public:
    32. Cat(string name)
    33. {
    34. //这李右边返回的是一个string的指针
    35. m_name=new string(name);//这个不仅能开辟空间还能传入地址就是将name 的地址床给m_name
    36. cout<<"Cat构造函数的调用"<<endl;
    37. }
    38. ~Cat()
    39. {
    40. if(m_name!=NULL)
    41. {
    42. delete m_name;
    43. m_name=NULL;
    44. cout<<"Cat析构函数的调用"<<endl;
    45. }
    46. }
    47. void speak()//如果抽象类中声明了任何类型的纯虚函数其子类都需要重写纯虚函数否则子类为 抽象类。
    48. {
    49. cout<<*m_name<<"小猫在说话"<<endl;
    50. }
    51. string *m_name;//将创建的小猫名称创建到堆区
    52. };
    53. void show()
    54. {
    55. Animal *animal=new Cat("Tom");
    56. animal->speak();
    57. //如果没有虚析构函数或纯虚析构函数时
    58. //父类指针在析构时候不会调用子类中的析构函数,子类中如果有堆区属性,就会出现内存泄露
    59. //别忘了创建后释放!!!
    60. delete animal;
    61. }
    62. int main()
    63. {
    64. show();
    65. }
    66. //定义虚析构函数和纯虚析构函数的条件
    67. //1在子类中有一些属性实在堆区的
    68. //
    69. //

    总结:
    1:虚析构和纯虚析构就是用来解决父类指针释放子类指针的现象。
    2:如果子类没有堆区数据,可以不写为虚析构或纯虚析构函数。
    3:拥有纯虚析构函数的类也属于抽象类。