继承多态

1.继承的构造和析构的顺序

子类继承父类:
(1)父类构造函数
(2)子类构造函数
(3)子类析构函数
(4)父类析构函数

不管怎么调用子类结果都是一样的:

//通过父类创建子类
Animal *cat = new Cat();
delete cat;
cat = NULL;
cout<<endl;
//子类自己创建自己
Cat *c = new Cat();
delete c;
c = NULL;
cout<<endl;
//或者非指针的方式
Cat cat1;

image
(后面少截了一段)

2. 父类释放子类指针问题

现在子类存在带有指针的类:
父类Animal.hpp:

//
// Created by Administrator on 2021/7/16.
//

#ifndef C__TEST01_ANIMAL_HPP
#define C__TEST01_ANIMAL_HPP
#include "iostream"

class Animal {
public:
    string *name;
public:
    Animal();
    //virtual ~Animal() = 0; //纯虚析构,纯虚析构必须在类外实现
    ~Animal();//没用虚析构的情况
    virtual void doSpeak() = 0;//纯虚函数,相当于java的接口,子类必须重写父类方法
};

Animal::Animal() {
    name = new string("animal");
    cout<<"Animal abstract class construction"<<endl;
}

//为了帮助解决父类释放子类指针的问题
Animal::~Animal() {
    if(name !=NULL)
    {
        delete name;
        name = NULL;
    }
    cout<<"Animal Destructor"<<endl;
}

#endif //C__TEST01_ANIMAL_HPP

子类Cat.hpp:

//
// Created by Administrator on 2021/7/16.
//

#ifndef C__TEST01_CAT_HPP
#define C__TEST01_CAT_HPP

#include "iostream"
#include "Animal.hpp"

class Cat :public Animal{
private:
    string *name;
public:
    Cat();
    ~Cat();
    virtual void doSpeak();
};

Cat::Cat() {
    name = new string("tom");
    cout<<"Cat class construction"<<endl;
}
Cat::~Cat() {
    if(name !=NULL)
    {
        delete name;
        name = NULL;
    }
    cout<<"Cat Destructor"<<endl;
}

void Cat::doSpeak() {
    cout<<name<<"在说话函数"<<endl;
}
#endif //C__TEST01_CAT_HPP

我们再在main中调用:

#include <iostream>
using namespace std;

//类的继承多态
#include "Cat.hpp"
int main() {
    //通过父类创建子类
    Animal *cat = new Cat();
    delete cat;
    cat = NULL;
    cout<<endl;
    //子类自己创建自己
    Cat *c = new Cat();
    delete c;
    c = NULL;
    cout<<endl;

    Cat cat1;
    return 0;
}

结果:
image
从结果可知:第一个用父类指针new子类, 父类并不能释放子类指针!
但是直接子类new子类就不会出现问题,我们在实际应用中肯定会用父类new子类,所以解决办法就是将父类的析构函数换成纯虚析构或者虚析构函数:
代码只需加个virtual:

//
// Created by Administrator on 2021/7/16.
//

#ifndef C__TEST01_ANIMAL_HPP
#define C__TEST01_ANIMAL_HPP
#include "iostream"

class Animal {
public:
    string *name;
public:
    Animal();
    virtual ~Animal() = 0; //纯虚析构,纯虚析构必须在类外实现
    //~Animal();//没用虚析构的情况
    virtual void doSpeak() = 0;//纯虚函数,相当于java的接口,子类必须重写父类方法
};

Animal::Animal() {
    name = new string("animal");
    cout<<"Animal abstract class construction"<<endl;
}

//为了帮助解决父类释放子类指针的问题
Animal::~Animal() {
    if(name !=NULL)
    {
        delete name;
        name = NULL;
    }
    cout<<"Animal Destructor"<<endl;
}

#endif //C__TEST01_ANIMAL_HPP

再看结果,这样就解决了问题:
image
(后面少截了一段)

posted @   蘑菇王国大聪明  阅读(59)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示