C++学习笔记(38):封装、继承、多态

什么是接口

arduino 复制代码
我定义了一个类对象,这个类的public公共函数,就是接口;而private私有函数,就不是接口。
我实现了一个动态库,动态库开放出来的函数,就是接口;而动态库封装到实现内部的函数,就不是接口。
我写了一个程序A,想给另一个同事B使用,我们之间就要约定好接口。这个接口就是我给他提供什么公共函数,给他提供什么样子的数据结构体,这些都是接口。
在QT中,会有信号槽的概念,信号,也是接口;公共槽函数,也是接口;私有槽函数,就不是接口。

接口的工程意义

  • 动态库的.h头文件就是接口
  • 我给别人提供的函数声明是接口
  • QT的信号是接口:"我告诉你我什么时候会发出什么信号"

封装:把复杂装进"黑盒子"

封装的本质就是造黑盒子:把复杂的内部实现藏起来,只是暴露简单的使用接口。

  • 可以封装为函数:实现特定功能的函数接口
  • 封装为类:合理抽象出来的类
  • 封装为模块:实现复杂功能集合的功能模块,供他人使用
  • 封装为dll:封装为动态库,基于头文件供他人使用

判断封装的好坏:高内聚,松耦合 高内聚:一个模块内部联系紧密 松耦合:模块之间依赖简单清晰

继承

继承的本质是代码复用和概念分层。 继承的工程价值:

  • 代码复用:公共功能在基类实现一次
  • 概念抽象:不同相机都是"一种相机"
  • 扩展方便:新相机类型只需要实现差异部分

多态:同一接口,千变万化

多态就是"一个接口,多种实现",让代码具备运行时灵活性。

arduino 复制代码
多态按字面的意思就是多种形态。
当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
在 C++ 中,多态(Polymorphism)是面向对象编程的重要特性之一。
C++ 多态允许使用基类指针或引用来调用子类的重写方法,从而使得同一接口可以表现不同的行为。
多态使得代码更加灵活和通用,程序可以通过基类指针或引用来操作不同类型的对象,而不需要显式区分对象类型。这样可以使代码更具扩展性,在增加新的形状类时不需要修改主程序。

以下是多态的几个关键点:
虚函数(Virtual Functions):
在基类中声明一个函数为虚函数,使用关键字virtual。
派生类可以重写(override)这个虚函数。
调用虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。

动态绑定(Dynamic Binding):
也称为晚期绑定(Late Binding),在运行时确定函数调用的具体实现。
    需要使用指向基类的指针或引用来调用虚函数,编译器在运行时根据对象的实际类型来决定调用哪个函数。
    
纯虚函数(Pure Virtual Functions):
一个包含纯虚函数的类被称为抽象类(Abstract Class),它不能被直接实例化。
纯虚函数没有函数体,声明时使用= 0。
它强制派生类提供具体的实现。

多态的实现机制:
虚函数表(V-Table):C++运行时使用虚函数表来实现多态。每个包含虚函数的类都有一个虚函数表,表中存储了指向类中所有虚函数的指针。
虚函数指针(V-Ptr):对象中包含一个指向该类虚函数表的指针。

哈哈哈哈

arduino 复制代码
#include <iostream>
using namespace std;

// 基类 Animal
class Animal {
public:
    // 虚函数 sound,为不同的动物发声提供接口
    virtual void sound() const {
        cout << "Animal makes a sound" << endl;
    }

    // 虚析构函数确保子类对象被正确析构
    virtual ~Animal() { 
        cout << "Animal destroyed" << endl; 
    }
};

// 派生类 Dog,继承自 Animal
class Dog : public Animal {
public:
    // 重写 sound 方法
    void sound() const override {
        cout << "Dog barks" << endl;
    }

    ~Dog() {
        cout << "Dog destroyed" << endl;
    }
};

// 派生类 Cat,继承自 Animal
class Cat : public Animal {
public:
    // 重写 sound 方法
    void sound() const override {
        cout << "Cat meows" << endl;
    }

    ~Cat() {
        cout << "Cat destroyed" << endl;
    }
};

// 测试多态
int main() {
    Animal* animalPtr;  // 基类指针

    // 创建 Dog 对象,并指向 Animal 指针
    animalPtr = new Dog();
    animalPtr->sound();  // 调用 Dog 的 sound 方法
    delete animalPtr;    // 释放内存,调用 Dog 和 Animal 的析构函数

    // 创建 Cat 对象,并指向 Animal 指针
    animalPtr = new Cat();
    animalPtr->sound();  // 调用 Cat 的 sound 方法
    delete animalPtr;    // 释放内存,调用 Cat 和 Animal 的析构函数

    return 0;
}

运行结果:

virtual 关键字:多态的开关

总结:面向对象的工程思维

  • 接口:定义"怎么用",隐藏"怎么实现"
  • 封装:制造"黑盒子",管理复杂度
  • 继承:建立"是什么"关系,复用代码
  • 多态:实现"一个接口,多种行为"
相关推荐
6Hzlia2 小时前
【Hot 100 刷题计划】 LeetCode 54. 螺旋矩阵 | C++ 模拟法题解
c++·leetcode·矩阵
梓䈑2 小时前
Gflags解剖课:从DEFINE宏到命令行解析的工程化实践
c++·gflags
Tanecious.2 小时前
蓝桥杯备赛:Day8-小红杀怪
c++·蓝桥杯
wregjru3 小时前
【高并发服务器项目】2.服务器业务层设计详解
c++
样例过了就是过了3 小时前
LeetCode热题100 跳跃游戏 II
c++·算法·leetcode·贪心算法·动态规划
charlie1145141913 小时前
现代Qt开发——0.1——如何在IDE中配置Qt环境?
开发语言·c++·ide·qt·嵌入式
计算机安禾3 小时前
【数据结构与算法】第32篇:交换排序(一):冒泡排序
c语言·数据结构·c++·算法·链表·排序算法·visual studio code
胖咕噜的稞达鸭3 小时前
C/C++动态内存管理,malloc,calloc,realloc的区别,动态内存中的错误汇总
c语言·开发语言·c++
charlie1145141913 小时前
嵌入式C++教程实战之Linux下的单片机编程(6):从点亮第一盏LED开始 —— 我们为什么要用现代C++写STM32
linux·c语言·开发语言·c++·stm32·单片机