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;
    }
};
相关推荐
无名之逆7 分钟前
在Rust生态中探索高性能HTTP服务器:Hyperlane初体验
运维·服务器·开发语言·后端·http·rust·自动化
独好紫罗兰18 分钟前
洛谷题单3-P5724 【深基4.习5】求极差 最大跨度值 最大值和最小值的差-python-流程图重构
开发语言·python·算法
朝阳同学24 分钟前
C++中高精度运算问题
开发语言·c++
对方正在长头发丿27 分钟前
棋盘问题(DFS)
数据结构·c++·算法·蓝桥杯·深度优先
@蓝莓果粒茶29 分钟前
LeetCode第132题_分割回文串II
开发语言·算法·leetcode·职场和发展·c#·.net·linq
程序媛学姐1 小时前
SpringRabbitMQ消息发送:RabbitTemplate与消息确认
java·开发语言·spring
mxd018481 小时前
sojson。v5:新一代JavaScript代码保护工具的技术解析与应用场景
开发语言·javascript·ecmascript
汐汐咯1 小时前
编程题学习
c++
孞㐑¥1 小时前
C++之红黑树
开发语言·c++·经验分享·笔记
今天也要早睡早起1 小时前
代码随想录算法训练营Day32| 完全背包问题(二维数组 & 滚动数组)、LeetCode 518 零钱兑换 II、377 组合总数 IV、爬楼梯(进阶)
数据结构·c++·算法·leetcode·动态规划·完全背包