LiSheng's blog LiSheng's blog
首页
笔记
个人简历
随笔集
GitHub (opens new window)
首页
笔记
个人简历
随笔集
GitHub (opens new window)
  • golang

  • cplus

    • 内存相关

    • 面向对象

      • 相关问题
      • 构造、析构顺序
      • 对象内存布局
      • 静态、动态多态
        • 虚函数表
        • 重载、重写、覆盖
        • 构造函数不能是虚函数
        • CRTP模式的原理和用途
        • 移动语义move
        • 构造函数初始化列表
        • 静态成员变量和函数
        • 多重继承
        • 菱形问题与虚继承
        • 对象池
      • STL相关

      • 内置数据结构
      • 数据结构示例
      • go和c++对比
      • 关键字

    • leetcode

    • 存储技术

    • 分布式系统

    • 计算机网络

    • Linux操作系统

    • Redis

    • 其他

    • 笔记
    • cplus
    • 面向对象
    lisheng
    2024-09-10
    目录

    静态、动态多态

    C++中的多态性(Polymorphism)是一种面向对象编程的重要特性,它允许不同的对象以统一的接口进行操作。在C++中,多态性主要通过编译时多态(静态多态)和运行时多态(动态多态)两种方式实现。

    # 一、编译时多态(静态多态)

    编译时多态是在编译时确定的多态性,主要通过函数重载、运算符重载和模板实现。

    1. 函数重载(Function Overloading)

      • 同一作用域内定义多个函数,它们具有相同的函数名,但参数列表不同。
      • 根据传入的参数类型和数量,在编译时确定调用哪个函数。
      void print(int i) {
          std::cout << "Printing int: " << i << std::endl;
      }
      
      void print(double d) {
          std::cout << "Printing double: " << d << std::endl;
      }
      
      void print(const std::string& s) {
          std::cout << "Printing string: " << s << std::endl;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    2. 运算符重载(Operator Overloading)

      • 允许重载C++中的运算符,使其能够处理用户定义的类型。
      class Complex {
      public:
          double real, imag;
          Complex(double r, double i) : real(r), imag(i) {}
      
          Complex operator+(const Complex& other) {
              return Complex(real + other.real, imag + other.imag);
          }
      };
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    3. 模板(Templates)

      • 模板是C++提供的一种泛型编程机制,可以在编译时生成不同类型的代码,实现类型参数化。
      template <typename T>
      T add(T a, T b) {
          return a + b;
      }
      
      1
      2
      3
      4

    # 二、运行时多态(动态多态)

    运行时多态是在程序运行时通过基类指针或引用调用派生类的函数实现的多态性。主要通过虚函数和继承实现。

    1. 虚函数(Virtual Function)

      • 在基类中声明一个函数为 virtual,允许派生类重写该函数。
      • 使用基类指针或引用调用该函数时,会根据实际指向的对象类型调用对应的派生类实现。
      class Base {
      public:
          virtual void show() {
              std::cout << "Base show" << std::endl;
          }
      };
      
      class Derived : public Base {
      public:
          void show() override {
              std::cout << "Derived show" << std::endl;
          }
      };
      
      int main() {
          Base* ptr = new Derived();
          ptr->show(); // 调用的是 Derived::show
          delete ptr;
          return 0;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
    2. 纯虚函数与抽象类

      • 如果在基类中将虚函数声明为纯虚函数(virtual void func() = 0;),则该类为抽象类,不能实例化。
      • 派生类必须重写所有的纯虚函数,才能实例化派生类对象。
      class AbstractBase {
      public:
          virtual void show() = 0; // 纯虚函数
      };
      
      class Derived : public AbstractBase {
      public:
          void show() override {
              std::cout << "Derived show" << std::endl;
          }
      };
      
      int main() {
          Derived d;
          d.show(); // 调用 Derived::show
          return 0;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
    3. 虚析构函数

      • 当一个类具有虚函数时,通常应将其析构函数也定义为虚函数,以确保在通过基类指针删除派生类对象时,派生类的析构函数能够被正确调用,防止资源泄漏。
      class Base {
      public:
          virtual ~Base() {
              std::cout << "Base Destructor" << std::endl;
          }
      };
      
      class Derived : public Base {
      public:
          ~Derived() {
              std::cout << "Derived Destructor" << std::endl;
          }
      };
      
      int main() {
          Base* ptr = new Derived();
          delete ptr; // 调用的是 Derived 的析构函数,然后是 Base 的析构函数
          return 0;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19

    # 三、多态性的实现原理

    C++运行时多态的底层实现依赖于虚函数表(Virtual Table,vtable)和虚函数表指针(vptr)。

    1. 虚函数表(vtable):

      • 每个包含虚函数的类都对应一个虚函数表,表中存储了类的虚函数指针。
      • 派生类的虚函数表会覆盖或继承基类的虚函数表中的函数指针。
    2. 虚函数表指针(vptr):

      • 每个对象都有一个隐藏的指针(vptr),指向其所属类的虚函数表。
      • 在调用虚函数时,通过vptr找到虚函数表,再从表中找到对应的函数指针,最终调用实际的函数实现。

    通过这种机制,C++实现了运行时多态,使得在基类指针或引用调用时,能够正确调用派生类的重写函数。

    # 总结

    • 编译时多态:通过函数重载、运算符重载和模板实现,在编译时决定调用哪个函数或操作符。
    • 运行时多态:通过虚函数和继承实现,在运行时根据对象的实际类型动态调用函数。

    了解这些多态性机制及其实现原理对于掌握C++面向对象编程非常重要,也是面试中常见的考点。

    编辑 (opens new window)
    上次更新: 2024/09/13, 11:59:12
    对象内存布局
    虚函数表

    ← 对象内存布局 虚函数表→

    最近更新
    01
    ceph分布式存储-对象存储(RGW)搭建
    10-27
    02
    ceph分布式存储-集群客户端连接
    10-27
    03
    ceph分布式存储-管理crushmap
    10-27
    更多文章>
    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式