C++析构函数定义为virtual虚函数,有什么作用?

简介: C++析构函数定义为virtual虚函数,有什么作用?

C++析构函数定义为virtual虚函数,有什么作用?

简介:析构函数定义为virtual虚函数,有什么作用?

代码讲解

简单的说,C++中基类采用virtual虚析构函数是为了防止内存泄漏,如果派生类中申请了内存空间,并在析构函数中对这些内存空间进行了释放。

如果这个时候基类中采取的是非虚构函数,那么当删除基类指针的死后,指向派生类对象的时候就不会发生动态绑定,导致的结果就是,调用基类的析构函数,而不会调用派生类的析构函数。

再这样的情况下对于派生类申请的空间就得不到释放从而产生了内存泄漏。

为了防止这样的情况发生,C++中基类的析构函数就需要采取virtual的虚构函数,实现动态绑定,这样才可以。

至于什么是动态绑定与静态绑定可以看看这篇文章:动态多态与静态多态

学习代码:

#include<iostream>
using namespace std;
class A
{
public:
    A(){
    }
    ~A(){
        cout << "A discontruct" << endl;
    }
  virtual string OnPaint() = 0; // 定义接口
};
class B : public A
{
public:
  virtual string OnPaint()
  {
    cout<< "B" << endl;
    return "B";
  }
  ~B(){
      cout << "B discontruct" << endl;
  }
};
class C : public A
{
public:
  virtual string OnPaint()
  {
    cout<< "C" << endl;
    return "C";
  }
  ~C(){
      cout << "C discontruct" << endl;
  }
};
int main()
{
  A* p = new B();
  p->OnPaint(); // B
  delete p;
  p = new C(); 
  p->OnPaint(); // C
  delete p;
  return 0;
}

运行结果

通过运行结果我们可以发现,派生类的内存没有得到释放。

改进办法

#include<iostream>
using namespace std;
class A
{
public:
    A(){
    }
    virtual ~A(){
        cout << "A discontruct" << endl;
    }
  virtual string OnPaint() = 0; // 定义接口
};
class B : public A
{
public:
  virtual string OnPaint()
  {
    cout<< "B" << endl;
    return "B";
  }
  virtual ~B(){
      cout << "B discontruct" << endl;
  }
};
class C : public A
{
public:
  virtual string OnPaint()
  {
    cout<< "C" << endl;
    return "C";
  }
  virtual ~C(){
      cout << "C discontruct" << endl;
  }
};
int main()
{
  A* p = new B();
  p->OnPaint(); // B
  delete p;
  p = new C(); 
  p->OnPaint(); // C
  delete p;
  return 0;
}

运行结果

通过把析构函数定义为虚函数,实现了派生类的内存释放。

相关文章
|
2月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
156 6
|
4月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
89 4
|
4月前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
87 3
|
6月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
346 4
|
6月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
409 4
|
7月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
103 2
|
7月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
97 1
|
8月前
|
C++
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
|
9月前
|
编译器 C++ 索引
C++虚拟成员-虚函数
C++虚拟成员-虚函数
|
9月前
|
编译器 C++
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
116 0