cpp自学 day19(多态)

一、基本概念

同一操作作用于不同的对象,产生不同的执行结果

👉 就像「按F1键」:在Word弹出帮助文档,在PS弹出画笔设置,​同一个按键触发不同功能


(1)多态类型

类型 实现方式 绑定时机
静态多态 函数重载、运算符重载 编译时绑定
动态多态 虚函数+继承体系 运行时绑定

(2)动态多态三要素

多态满足条件
  • 有继承关系
  • 子类重写父类中的虚函数
多态使用条件
  • 父类指针或引用指向子类对象
    重写:函数返回值类型 函数名 参数列表 完全一致称为重写 (缺一不可)
cpp 复制代码
class 父类名 {
public:
    virtual 返回类型 函数名(参数列表) {
        // 函数体
    }
};

(3)示例代码

cpp 复制代码
// 父类
class Animal {
public:
    virtual void speak() {  // 1. 虚函数声明
        cout << "动物发声" << endl;
    }
};

// 子类
class Cat : public Animal { // 1. 继承关系
public:
    void speak() override { // 2. 重写虚函数
        cout << "喵喵" << endl; 
    }
};

// 多态调用
void doSpeak(Animal& animal) { // 3. 父类引用接收子类对象
    animal.speak(); // 运行时决定调用哪个实现
}

void doSpeak(Animal *animal) {// 4.用指针接收子类对象
    animal->speak();
}

void test() {
    Cat cat;
    doSpeak(cat); // 输出:喵喵
}

(4)重要特性

函数重写严格一致:(此处是函数内参数不一致)

cpp 复制代码
// 错误示例:参数不同
class Animal { virtual void func(int) };
class Cat : public Animal { void func() }; // 不会触发多态

二、多态原理

当子类重写父类的虚函数,子类中的虚函数表内部,会替换成 子类的虚函数地址

cpp 复制代码
class Animal
{
public:
    //虚函数
    virtual void speak()
    {
        cout << "动物在说话" << endl;
    }
};
cpp 复制代码
//猫类
class Cat : public Animal
{
public:
    //重写 函数返回值类型 函数名 参数列表 完全相同
    virtual void speak()
    {
        cout << "小猫在说话" << endl;
    }
};

原理概况

当父类的指针或者引用指向子类对象时候,发生多态

cpp 复制代码
Animal & animal = cat;
animal.speak();
cpp 复制代码
vfptr - 虚函数(表)指针

v - virtual
f - function
ptr - pointer

vtable - 虚函数表

v - virtual
f - function
table - table

三、纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数,当类中有了纯虚函数,这个类也称为抽象类
纯虚函数语法:virtual 返回值类型 函数名(参数列表)= 0 ;

复制代码
 virtual void func() = 0;

抽象类特点:

1、无法实例化对象

cpp 复制代码
若Base是抽象类,则下面两行报错
Base b;
new Base;

2、子类必须重写抽象类中的纯虚函数,否则也属于抽象类

++写纯虚函数意义就是想让子类重写一遍纯虚函数++


四、虚析构与纯虚析构

1.核心问题

内存泄漏场景

cpp 复制代码
class Animal {
public:
    ~Animal() {  // ❌ 普通析构
        cout << "Animal析构" << endl;
    }
};

class Cat : public Animal {
public:
    ~Cat() {
        cout << "Cat析构" << endl;
        delete[] m_data;  // 堆内存资源
    }
private:
    int* m_data = new int[100];
};

void test() {
    Animal* pet = new Cat();
    pet->speak();
    delete pet;  // 仅调用Animal析构 → 内存泄漏!
}

执行结果

cpp 复制代码
Animal析构
(Cat析构未被调用 → m_data内存泄漏)

2.解决方案对比

方案类型 语法示例 类性质 实现要求 使用场景
虚析构 virtual ~Animal() {} 普通类 必须实现 需要实例化基类对象
纯虚析构 virtual ~Animal() = 0; 抽象类 必须单独实现 强制子类实现特定行为

3.具体实现

1. 虚析构函数

cpp 复制代码
class Animal {
public:
    virtual ~Animal() {  // ✅ 虚析构声明
        cout << "Animal虚析构" << endl;
    }
};

// 正确执行结果:
// Cat析构
// Animal虚析构

2. 纯虚析构函数

cpp 复制代码
class Animal {
public:
    virtual ~Animal() = 0;  // 纯虚析构声明
};

// 必须单独实现
Animal::~Animal() {  // ✅ 纯虚析构实现
    cout << "Animal纯虚析构" << endl;
}

特性

  • 使类成为抽象类(无法实例化)
  • 子类必须实现析构函数
cpp 复制代码
class Cat : public Animal {
public:
    ~Cat() override {  // 必须实现
        cout << "Cat析构" << endl;
    }
};
相关推荐
荒川之神5 分钟前
拉链表概念与基本设计
java·开发语言·数据库
chushiyunen15 分钟前
python中的@Property和@Setter
java·开发语言·python
小樱花的樱花22 分钟前
C++ new和delete用法详解
linux·开发语言·c++
froginwe1123 分钟前
C 运算符
开发语言
fengfuyao9851 小时前
低数据极限下模型预测控制的非线性动力学的稀疏识别 MATLAB实现
开发语言·matlab
摇滚侠1 小时前
搭建前端开发环境 安装 nodejs 设置淘宝镜像 最简化最标准版本 不使用 NVM NVM 高版本无法安装低版本 nodejs
java·开发语言·node.js
t198751281 小时前
MATLAB十字路口车辆通行情况模拟系统
开发语言·matlab
yyk的萌1 小时前
AI 应用开发工程师基础学习计划
开发语言·python·学习·ai·lua
Amumu121382 小时前
Js:正则表达式(一)
开发语言·javascript·正则表达式
努力的章鱼bro3 小时前
操作系统-FileSystem
c++·操作系统·risc-v·filesystem