当前位置: 首页 > news >正文

C++_多态和虚构

在C++的类继承中,多态(Polymorphism) 和 虚析构函数(Virtual Destructor) 是两个紧密相关且非常重要的概念,它们共同确保了面向对象编程中动态行为的正确性和资源的安全释放。
一、多态(Polymorphism)

多态是C++面向对象的三大特性之一(封装、继承、多态),它允许同一个接口调用不同的实现。在C++中,多态主要通过虚函数(virtual functions) 实现。

  1. 虚函数(Virtual Function)

    在基类中使用 virtual 关键字声明的成员函数。
    派生类可以重写(override)该函数,提供自己的实现。
    当通过基类指针或引用调用虚函数时,会根据实际对象的类型来决定调用哪个版本的函数,这就是动态绑定(Dynamic Binding)。


#include <iostream>
using namespace std;class Animal {
public:virtual void makeSound() {cout << "Animal makes a sound" << endl;}
};class Dog : public Animal {
public:void makeSound() override {  // override 关键字可选,但推荐使用cout << "Woof!" << endl;}
};class Cat : public Animal {
public:void makeSound() override {cout << "Meow!" << endl;}
};int main() {Animal* animal1 = new Dog();Animal* animal2 = new Cat();animal1->makeSound(); // 输出: Woof!animal2->makeSound(); // 输出: Meow!delete animal1;delete animal2;return 0;
}
注意:如果没有 virtual,则调用的是基类的 makeSound(),这就是静态绑定。

二、虚析构函数(Virtual Destructor)

  1. 为什么需要虚析构函数?

当你通过基类指针删除一个派生类对象时,如果基类的析构函数不是虚的,那么只有基类的析构函数会被调用,派生类的析构函数不会被调用,这会导致资源泄漏(如内存、文件句柄等未正确释放)。


class Base {
public:~Base() {cout << "Base destructor" << endl;}
};class Derived : public Base {int* data;
public:Derived() { data = new int(10); }~Derived() {delete data;cout << "Derived destructor" << endl;}
};int main() {Base* ptr = new Derived();delete ptr;  // 只调用 Base 的析构函数!// Derived 的析构函数不会被调用!// data 指针泄漏!return 0;
}
  1. 解决方案:将基类的析构函数声明为 virtual

class Base {
public:virtual ~Base() {  // 虚析构函数cout << "Base destructor" << endl;}
};class Derived : public Base {int* data;
public:Derived() { data = new int(10); }virtual ~Derived() {  // 派生类析构函数自动成为虚函数(可加 virtual,也可不加)delete data;cout << "Derived destructor" << endl;}
};int main() {Base* ptr = new Derived();delete ptr;  // 先调用 Derived 的析构函数,再调用 Base 的析构函数return 0;
}
输出:深色版本Derived destructor
Base destructor
  1. 最佳实践

    只要一个类被设计为基类(即可能被继承),其析构函数就应该声明为 virtual。
    即使析构函数是空的,也应声明为 virtual。
    虚析构函数会带来轻微的性能开销(虚函数表查找),但在大多数情况下这是值得的。

三、总结
概念 作用 关键点
多态 实现运行时动态调用 使用 virtual 函数,通过基类指针/引用调用
虚析构函数 确保派生类对象被正确销毁 基类析构函数必须是 virtual,否则可能导致资源泄漏

✅ 记住:“有虚函数,就有虚析构函数”。如果一个类有虚函数,通常意味着它会被继承和多态使用,因此析构函数必须是虚的。

补充:纯虚函数与抽象类


class Shape {
public:virtual void draw() = 0;  // 纯虚函数virtual ~Shape() = default; // 虚析构函数,推荐写成 default
};class Circle : public Shape {
public:void draw() override {cout << "Drawing a circle" << endl;}~Circle() override = default;
};
包含纯虚函数的类是抽象类,不能实例化。
子类必须实现所有纯虚函数,否则也是抽象类。
抽象基类必须有虚析构函数。
http://www.dtcms.com/a/358311.html

相关文章:

  • 卡片一放,服务直达!实现信息零层级触达
  • Python实现京东商品数据自动化采集的实用指南
  • (双指针)Leetcode283.移动零-替换数字类别+Leetcode15. 三数之和
  • UI前端大数据可视化实战策略:如何设计符合用户认知的数据可视化界面?
  • 【计算机网络】HTTP是什么?
  • Ansible Playbook 调试与预演指南:从语法检查到连通性排查
  • 一体化步进伺服电机在汽车线束焊接设备中的应用案例
  • MongoDB 源码编译与调试:深入理解存储引擎设计 内容详细
  • HarmonyOS元服务开发
  • 深入解析HarmonyOS:UIAbility与Page的生命周期协同
  • TensorFlow 面试题及详细答案 120道(71-80)-- 性能优化与调试
  • 坚鹏请教DEEPSEEK:请问中国领先的AI智能体服务商有哪些?知行学
  • 深度学习系列 | Seq2Seq端到端翻译模型
  • 离线大文件与断点续传:ABP + TUS + MinIO/S3
  • IAR工程如何搭建vscode+clangd编辑环境
  • 如何使用快照将 AWS OpenSearch 服务中的数据从开发环境复制到生产环境
  • 互联网医院系统优势介绍
  • 嵌入式linux相机(2)
  • 设计模式 - 静态工厂模式 + 策略模式,
  • 【Java后端】MySQL 常见 SQL 语句优化指南
  • AI 赋能综合能源管理系统:开启智慧能源新时代
  • 掌握表单:React中的受控组件与表单处理
  • 详解Vue2、Vue3与React的Diff算法
  • 【Android】OkHttp发起GET请求 POST请求
  • React Router 6 获取路由参数
  • 【自然语言处理与大模型】如何进行大模型多模态微调
  • 【ASP.NET Core】双Token机制在ASP.NET Core中的实现
  • OpenCV 图像形态学操作与边缘检测实战指南
  • ESPTimer vs GPTimer:ESP32 定时器系统深度解析
  • 机器学习 - Kaggle项目实践(6)Dogs vs. Cats Redux: Kernels Edition 猫狗二分类