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

C++ 多态

本文部分代码通过DeepSeek生成


创建一个基类和一个子类。

基类 Animal 包含一个虚函数 makeSound(),子类 Dog 继承自 Animal 并重写了 makeSound() 函数。

#include <iostream>
#include <string>

// 基类 Animal
class Animal {
public:
    // 构造函数
    Animal(const std::string& name) : name(name) {}

    // 虚函数,子类可以重写
    virtual void makeSound() const {
        std::cout << name << " makes a sound." << std::endl;
    }

    // 虚析构函数,确保正确释放资源
    virtual ~Animal() {}

protected:
    std::string name;
};

// 子类 Dog,继承自 Animal
class Dog : public Animal {
public:
    // 构造函数
    Dog(const std::string& name) : Animal(name) {}

    // 重写基类的虚函数
    void makeSound() const override {
        std::cout << name << " says: Woof! Woof!" << std::endl;
    }
};

int main() {
    // 创建基类对象
    Animal* myAnimal = new Animal("Generic Animal");
    myAnimal->makeSound();  // 输出: Generic Animal makes a sound.
    delete myAnimal;

    // 创建子类对象
    Animal* myDog = new Dog("Buddy");
    myDog->makeSound();  // 输出: Buddy says: Woof! Woof!
    delete myDog;

    return 0;
}

代码说明:

  1. 基类 Animal:

    • 包含一个成员变量 name,用于存储动物的名字。

    • 包含一个虚函数 makeSound(),子类可以重写这个函数。

    • 包含一个虚析构函数,确保在删除派生类对象时正确调用析构函数

  2. 子类 Dog:

    • 继承自 Animal,并重写了 makeSound() 函数,使其输出狗的声音。

    • 使用 override 关键字明确表示重写基类的虚函数

  3. main 函数:

    • 创建了一个 Animal 对象和一个 Dog 对象,并调用它们的 makeSound() 函数。

    • 使用 delete 释放动态分配的内存

 


在 C++ 中,虚析构函数的作用是确保在通过基类指针删除派生类对象时,能够正确调用派生类的析构函数。如果没有虚析构函数,可能会导致派生类的析构函数不被调用,从而引发资源泄漏或其他未定义行为

为什么需要虚析构函数?

当使用基类指针指向派生类对象时,如果基类的析构函数不是虚函数,那么当删除该指针时,只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类中分配的资源(如动态内存、文件句柄等)无法正确释放。

示例代码

以下是一个示例,展示了虚析构函数的作用:

#include <iostream>

// 基类
class Base {
public:
    Base() {
        std::cout << "Base constructor called." << std::endl;
    }

    // 虚析构函数
    virtual ~Base() {
        std::cout << "Base destructor called." << std::endl;
    }
};

// 派生类
class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor called." << std::endl;
    }

    ~Derived() {
        std::cout << "Derived destructor called." << std::endl;
    }
};

int main() {
    // 使用基类指针指向派生类对象
    Base* ptr = new Derived();

    // 删除指针
    delete ptr; // 正确调用派生类和基类的析构函数

    return 0;
}

输出结果

Base constructor called.
Derived constructor called.
Derived destructor called.
Base destructor called.

关键点

  1. 虚析构函数的作用

    • 当 delete 一个基类指针时,如果基类的析构函数是虚函数,程序会先调用派生类的析构函数,再调用基类的析构函数

    • 如果基类的析构函数不是虚函数,则只会调用基类的析构函数,而不会调用派生类的析构函数

  2. 没有虚析构函数的情况
    如果去掉 Base 类析构函数的 virtual 关键字,输出将变为:

Base constructor called.
Derived constructor called.
Base destructor called.

可以看到,Derived 类的析构函数没有被调用,这可能导致资源泄漏。


  1. 何时使用虚析构函数

    • 如果一个类可能被继承,并且可能通过基类指针删除派生类对象,那么这个类的析构函数应该是虚函数

    • 如果类不会被继承,或者不会通过基类指针删除派生类对象,则不需要虚析构函数

总结

虚析构函数是 C++ 中多态性的重要组成部分,确保在删除派生类对象时能够正确调用派生类和基类的析构函数。在设计基类时,如果存在继承的可能性,务必为基类声明虚析构函数


 

相关文章:

  • 2.5 使用注解进行单元测试详解
  • 【vue3】实现pdf在线预览的几种方式
  • 论软件评估方法
  • rv1103b编译opencv
  • 家里装修想用投影仪,如何选择?装修中应该注意什么?
  • 浮点数二分
  • 数智化的力量:柏强制药构建医药高质量发展的新引擎
  • 场外个股期权下单后多久成交?场外个股期权对投资组合的影响
  • 《pyqt+open3d》第三章——icp配准点对面——稳健性提升
  • 【前端框架】Vue3 中 `setup` 函数的作用和使用方式
  • 【Elasticsearch】Token Graphs
  • 【LeetCode】739. 每日温度
  • rust学习二、入门之运行单个脚本
  • vue前端可视化大屏页面适配方案
  • 日本90年代经济泡沫初期是什么情况?
  • 面试经典150题——字典树
  • 深入探索xtquant:账户信息查询的全面指南
  • WPS中如何批量上下居中对齐word表格中的所有文字
  • DeepSeek的深度解析:由来、研发过程、公司背景、优势、劣势与总结
  • WSL Ubuntu 安装 CUDA 教程
  • wordpress主题改字体颜色/郑州官网网站推广优化公司
  • 网站怎么做百度权重/做销售有什么技巧和方法
  • 设计室内效果图设计/seo免费诊断
  • 怎么做网站优化推广/html网页制作模板代码
  • 做招聘的网站/360排名优化工具
  • wap建站程序/线上营销策略