C++复习笔记--虚析构和纯虚析构的使用

目录

1--前言

2--虚析构和纯虚析构

3--代码实例

3-1--父类对象无法调用子类析构函数

3-2--虚析构实现

3-3--纯虚析构实现


1--前言

        在使用多态时,如果子类的属性开辟到堆区,那么父类指针在释放时将无法调用子类的析构代码,此时需要将父类中的析构函数修改为虚析构或者纯虚析构;

2--虚析构和纯虚析构

① 虚析构和纯虚析构的共性:

        可以解决前言存在的问题,即解决父类指针无法调用子类析构函数释放堆区数据的问题;

        虚析构和纯虚析构都需要具体的函数实现,即需实现函数体的内容;

② 虚析构和纯虚析构的区别:

        纯虚析构的类为抽象类,不能实例化对象,而虚析构的类可以实例化对象;

// 虚析构语法:
virtual ~类名(){}
 
// 纯虚析构语法:
virtual ~类名() = 0;

3--代码实例

3-1--父类对象无法调用子类析构函数

# include 
# include 
 
class Animal{
public:
    // 纯虚函数
    Animal(){
        std::cout << "Animal的构造函数调用" << std::endl;
    }
    ~Animal(){
        std::cout << "Animal的析构函数调用" << std::endl;
    }
    virtual void speak() = 0;
};
 
class Cat :public Animal{
public:
 
    Cat(std::string name){
        std::cout << "Cat的构造函数调用" << std::endl;
        Name = new std::string(name);
    }
 
    virtual void speak(){
        std::cout << *Name << " Cat is speaking" << std::endl;
    }
 
    ~Cat(){
        if(Name != NULL){
            std::cout << "Cat的析构函数调用" << std::endl;
            delete Name;
            Name = NULL;
        }
    }
 
    std::string *Name;
};
 
int main(){
    Animal * animal = new Cat("Tom");
    animal->speak();
    // 父类指针析构时,不会调用子类的析构函数,如果子类含有堆区数据,会出现内存泄露
    delete animal; 
    return 0;
}

C++复习笔记--虚析构和纯虚析构的使用_第1张图片

        程序执行结果表明:没有调用子类 Cat 的析构函数,堆区数据无法有效释放,导致内存泄露;

3-2--虚析构实现

# include 
# include 

class Animal{
public:
    // 纯虚函数
    Animal(){
        std::cout << "Animal的构造函数调用" << std::endl;
    }
    // 利用虚析构可以解决父类指针释放子类对象的问题
    virtual ~Animal(){
        std::cout << "Animal的析构函数调用" << std::endl;
    }
    virtual void speak() = 0;
};

class Cat :public Animal{
public:

    Cat(std::string name){
        std::cout << "Cat的构造函数调用" << std::endl;
        Name = new std::string(name);
    }

    virtual void speak(){
        std::cout << *Name << " Cat is speaking" << std::endl;
    }

    ~Cat(){
        if(Name != NULL){
            std::cout << "Cat的析构函数调用" << std::endl;
            delete Name;
            Name = NULL;
        }
    }

    std::string *Name;
};

int main(){
    Animal * animal = new Cat("Tom");
    animal->speak();
    // 父类指针析构时,不会调用子类的析构函数,如果子类含有堆区数据,会出现内存泄露
    delete animal; 
    return 0;
}

C++复习笔记--虚析构和纯虚析构的使用_第2张图片

3-3--纯虚析构实现

# include 
# include 

class Animal{
public:
    // 纯虚函数
    Animal(){
        std::cout << "Animal的构造函数调用" << std::endl;
    }
    // 利用纯虚析构可以解决父类指针释放子类对象的问题
    // 纯虚析构
    virtual ~Animal() = 0;
    virtual void speak() = 0;
};

// 纯虚析构也需要具体实现
Animal::~Animal(){
    std::cout << "Animal的纯虚析构函数调用" << std::endl;
}

class Cat :public Animal{
public:

    Cat(std::string name){
        std::cout << "Cat的构造函数调用" << std::endl;
        Name = new std::string(name);
    }

    virtual void speak(){
        std::cout << *Name << " Cat is speaking" << std::endl;
    }

    ~Cat(){
        if(Name != NULL){
            std::cout << "Cat的析构函数调用" << std::endl;
            delete Name;
            Name = NULL;
        }
    }

    std::string *Name;
};

int main(){
    Animal * animal = new Cat("Tom");
    animal->speak();
    // 父类指针析构时,不会调用子类的析构函数,如果子类含有堆区数据,会出现内存泄露
    delete animal; 
    return 0;
}

C++复习笔记--虚析构和纯虚析构的使用_第3张图片

         通过实现父类的虚析构和纯虚析构,使得父类指针调用子类对象的析构函数,从而释放子类对象在堆区创建的数据,防止内存泄露;

你可能感兴趣的:(C++复习笔记,c++,开发语言)