一篇文章彻底弄懂C++虚函数的实现机制

一篇文章彻底弄懂C++虚函数的实现机制

介绍

C++的虚函数是实现多态的重要途径,本文将深入浅出地介绍C++虚函数的实现机制,希望能给大家带来一些帮助。

基本概念

静态绑定和动态绑定

在C++中,有两种绑定方式,即静态绑定(也称为静态链接)和动态绑定(也称为动态链接)。

静态绑定是指在编译期间确定函数的调用地址。这种方式的优点是执行速度快,缺点是不支持多态。

动态绑定是指在运行时确定函数的调用地址。这种方式支持多态,但执行速度稍慢。

多态

多态是指同一函数调用,由于对象不同可能会产生不同的行为。C++中的多态性可通过虚函数实现。经过虚函数声明的函数,可以在程序执行时动态地调用。

虚函数

C++中的虚函数是在基类中声明的,用virtual关键字修饰。在派生类中,如果定义了与基类同名、同参数列表的虚函数,则该函数会覆盖基类中的虚函数。

虚函数的调用有两种方式:静态绑定和动态绑定。静态绑定是指在编译期间确定虚函数的调用地址,适用于基类和派生类对象的普通函数调用;动态绑定是指在运行时根据对象的实际类型确定虚函数的调用地址,适用于基类指针或引用的虚函数调用。

虚函数的实现机制

在C++中,虚函数的实现机制主要基于虚函数表和虚函数指针。

虚函数表

每个包含虚函数的类都有一个虚函数表,用于存储该类所有虚函数的地址。虚函数表是一个只读的数据表,存储在程序的数据区,不同对象共享同一张虚函数表。

每个类只有一个虚函数表,而不是每个对象都有一个虚函数表。在类的构造函数中,将会产生一个隐式的指针vptr,并被初始化为虚函数表的地址。当派生类对基类虚函数进行覆盖时,基类中的虚函数表被派生类虚函数表所替换。

虚函数指针

每个包含虚函数的对象都有一个虚函数指针,用于指向该对象所属类的虚函数表。虚函数指针指向的虚函数表是在编译期间确定的,因此属于静态绑定。

虚函数调用

静态绑定的虚函数调用和普通的函数调用一样,通过函数名直接调用。静态绑定的虚函数调用的效率比动态绑定高,因为静态绑定是在编译期间确定函数地址的,省去了在运行时查找虚函数表的时间。

动态绑定的虚函数调用通过对象的虚函数指针来确定虚函数表,再根据虚函数表中的偏移量来确定实际调用的函数地址。动态绑定的虚函数调用相对于静态绑定而言效率低,因为需要在运行时查找虚函数表,并在虚函数表中查找偏移量。

示例说明

示例1

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void func() { cout << "Base::func()" << endl; }
};

class Derived : public Base
{
public:
    void func() { cout << "Derived::func()" << endl; }
};

int main()
{
    Base b;
    Derived d;
    b.func();
    d.func();
    Base* pb = &d;
    pb->func();
    return 0;
}

输出结果:

Base::func()
Derived::func()
Derived::func()

解释如下:

在第一个和第二个函数调用中,使用了静态绑定,直接调用了类自身的虚函数。在第三个函数调用中,使用了动态绑定,通过基类指针来调用派生类的虚函数,实现了多态。

示例2

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void func1() { cout << "Base::func1()" << endl; }
    virtual void func2() { cout << "Base::func2()" << endl; }
};

class Derived : public Base
{
public:
    void func1() { cout << "Derived::func1()" << endl; }
    void func2() { cout << "Derived::func2()" << endl; }
};

int main()
{
    Base b;
    Derived d;
    Base* pb = &b;
    pb->func1();
    pb->func2();
    pb = &d;
    pb->func1();
    pb->func2();
    return 0;
}

输出结果:

Base::func1()
Base::func2()
Derived::func1()
Derived::func2()

解释如下:

在第一个和第二个函数调用中,使用了静态绑定,直接调用了类自身的虚函数。在第三个和第四个函数调用中,使用了动态绑定,通过基类指针来调用派生类的虚函数,实现了多态。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一篇文章彻底弄懂C++虚函数的实现机制 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++详解如何实现动态数组

    C++中实现动态数组有多种方式,常见的包括使用指针和STL容器。下面简要介绍一下这两种实现方式。 使用指针实现动态数组 申请动态数组空间 在C++中,我们可以使用new关键字来动态申请内存空间,然后使用指针来存储这个内存地址。例如,我们可以使用以下代码申请一个长度为10的整型动态数组: int* arr = new int[10]; 访问动态数组元素 当我们…

    C 2023年5月23日
    00
  • C++ 通过pqxxlib库链接 PostgreSql数据库的详细过程

    C++ 是广泛使用的编程语言之一,与后端的数据库管理息息相关。其中,PostgreSQL 是一个功能齐全的开源对象-关系数据库管理系统,被广泛应用于 Web 应用程序的数据存储。在 C++ 中,通过使用 pqxxlib 库的链接,可以很方便地访问并操作 PostgreSQL 数据库。 下面是 C++ 通过 pqxxlib 库链接 PostgreSQL 数据库…

    C 2023年5月22日
    00
  • C语言杨辉三角两种实现方法

    C语言中,杨辉三角是一种常见的数学图形,它是在中国古代,杨辉发明并深入研究的一种二项式数列。在计算机编程中,我们可以用不同的算法来实现杨辉三角。本文将主要介绍两种C语言实现杨辉三角的方法。 方法一:使用二维数组 首先,我们可以使用二维数组来存储杨辉三角的值。杨辉三角有以下的性质: 任意一行的第一位和最后一位都是1; 从第三行开始,中间的数等于上一行的相邻两个…

    C 2023年5月23日
    00
  • JAVA实现简单抢红包算法(模拟真实抢红包)

    以下是详细的攻略: 思路 抢红包的本质是在给定的一段时间内,根据一定的规则将一定数量的钱随机分配给多个人。那么针对这个问题,我们可以想到以下的思路: 用户发送一个抢红包的请求,此时服务器会返回一个JSON格式的数据; 解析JSON数据,计算出当前用户分配到的红包金额; 将用户分配到的金额从红包总金额中减去,并保存到数据库中,便于后续查询。 代码实现 下面是使…

    C 2023年5月23日
    00
  • C++算法系列之日历生成的算法代码

    首先,这篇文章介绍了如何用 C++ 编写一个生成日历的算法。该算法基于一个假设:为了表示一个月的日历,我们只需要知道该月的第一天是星期几,和该月的天数。因此,我们可以先确定出每个月的第一天是星期几,然后再以此为基础,生成整个月的日历。 在代码实现方面,我们可以使用 C++ 的结构体来存储一个日期,并为它提供一些常用的方法,例如获取下一个日期、判断两个日期是否…

    C 2023年5月22日
    00
  • C语言实现学生信息管理系统开发

    C语言实现学生信息管理系统开发攻略 简介 学生信息管理系统是企事业单位、政府机关和社会组织等管理组织必不可少的一项基础工作,管理学生信息可以提高工作效率,有效保证了各项工作的有序开展。本文将以C语言为开发语言,实现学生信息管理系统的开发。 开发工具 开发学生信息管理系统的首选是C语言,然后我们需要一款好用的IDE进行编写,比如Visual Studio Co…

    C 2023年5月23日
    00
  • YOGA C740和YOGA C940应该如何选择 YOGA C740和YOGA C940详细评测对比

    YOGA C740和YOGA C940应该如何选择 硬件配置 YOGA C940和YOGA C740在硬件配置上有一定的差异,如下所示: 参数 YOGA C740 YOGA C940 CPU Intel i5/i7 Intel i7/i9 内存 8/12/16GB 8/12/16GB 存储 256/512/1TB 256/512/1TB 显卡 NVIDIA …

    C 2023年5月23日
    00
  • 现代配置YAML对比JSON优势分析

    简介 本文将从以下几个方面来详细讲解“现代配置YAML对比JSON优势分析”: YAML和JSON的区别和优势; YAML在实际使用中的示例。 YAML和JSON的区别和优势 YAML和JSON都是现代配置中常用的数据序列化格式。它们具有以下区别和优势: YAML优势 对象比JSON更易读; 支持注释,更加可读性、可维护性; 支持多种数据类型(除了数字和字符…

    C 2023年5月24日
    00
合作推广
合作推广
分享本页
返回顶部