C++多态中的虚函数表

虚函数表(图文详解) 本文讲解了虚函数表以及继承和多态常见的面试问题 阅读详情

C++中的虚函数表

之前的 C++ 继承中已经说过多态基本概念,这里不再赘述。文章中多处给出了类实例对象的内存布局,查看其内存布局时,使用 VS 工具 /d1 reportAllClassLayout 进行查看,关于这个工具的详细介绍,请点击这里。

虚函数表的原理解析

C++ 虚函数表主要出现在多态情况下。这里我们先从单继承下说明其虚函数表的原理,后面再说多继承情况下的。

每个有虚函数的类的实例对象都有一个虚函数表指针成员,该虚函数指针一般位于对象存储空间的起始位置(相较于对象存储空间的起始位置偏移量为 0),该虚函数表指针指向实例的虚函数表,该虚函数表就是实现多态的关键。实际上,任何继承于包含虚函数的基类的派生类的实例对象都有虚函数表指针成员,并且虚函数表中的函数地址都是基类的,其操作是由编译器自动添加到构造函数中的指令完成的。

接下来将从下面一段简单的代码:

class Animal
{
public:
    virtual void eat() { cout << "Animal::eat" << endl; }
    virtual void sleep() { cout << "Animal::sleep" << endl; }
    virtual void play() { cout << "Animal::play" << endl; }

private:
    string m_name;
    int m_age = 0;
};

class Cat : public Animal
{
public:
    virtual void eat() { cout << "Cat::eat" << endl; }
    virtual void sleep() { cout << "Cat::sleep" << endl; }
    virtual void play() { cout << "Cat::play" << endl; }
};

利用上面说的 VS 查看类实例的内存布局的功能,我们先来看一下 Animal 实例对象的内存布局如下:

> cl /d1 reportSingleClassLayoutAnimal CppTest.cpp
class Animal    size(48):
        +---
 0      | {vfptr}
 8      | ?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@ m_name
40      | m_age
        | <alignment member> (size=4)
        +---

Animal::$vftable@:
        | &Animal_meta
        |  0
 0      | &Animal::eat
 1      | &Animal::sleep
 2      | &Animal::play

Animal::eat this adjustor: 0
Animal::sleep this adjustor: 0
Animal::play this adjustor: 0

上面说过,只要一个类中含有虚函数成员,其实例对象一定包含一个虚函数表,可以看到,首地址成员是一个 vfptr 虚函数表指针,其虚函数表中的成员就有基类中定义的三个函数。

现在我们仅使用派生类 Cat 继承于基类 Animal,不重写基类的方法,而且保持派生类的成员为空,将派生类改写成如下:

class Cat : public Animal
{
};

再看派生类 Cat 实例对象的内存布局如下:

> cl /d1 reportSingleClassLayoutCat CppTest.cpp
class Cat       size(48):
        +---
 0      | +--- (base class Animal)
 0      | | {vfptr}
 8      | | ?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@ m_name
40      | | m_age
        | | <alignment member> (size=4)
        | +---
        +---

Cat::$vftable@:
        | &Cat_meta
        |  0
 0      | &Animal::eat
 1      | &Animal::sleep
 2      | &Animal::play

可以证明,只要继承了包含虚函数成员的基类的派生类实例对象都包含有一个虚函数表指针成员。如果我们并没有重写基类的虚函数,其派生类中的虚函数表的中的虚函数地址全部都是基类的。

接下列,将派生类改写成如下:

class Cat : public Animal
{
public:
    virtual void eat() { cout << "Cat::eat" << endl; }
    virtual void sleep() { cout << "Cat::sleep" << endl; }
};

现在再讨论派生类 Cat 的实例对象内存布局,这个是重点讨论的对象,先看其内存布局如下:

> cl /d1 reportSingleClassLayoutCat CppTest.cpp
class Cat       size(48):
        +---
 0      | +--- (base class Animal)
 0      | | {vfptr}
 8      | | ?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@ m_name
40      | | m_age
        | | <alignment member> (size=4)
        | +---
        +---

Cat::$vftable@:
        | &Cat_meta
        |  0
 0      | &Cat::eat
 1      | &Cat::sleep
 2      | &Animal::play

Cat::eat this adjustor: 0
Cat::sleep this adjustor: 0

代码中,派生类 Cat 中重写了基类的 Animal 的虚函数 eat() 和 sleep(),我们看到派生类 Cat 的实例对象的虚函数表中的 eat 和 sleep 方法已经是派生类的实现的函数地址,没有重写基类的 play() 虚函数,在派生类的实例对象的虚函数表中的 play 方法还是基类中的函数地址。

想要达到多态的前提是:必须使用基类的指针变量指向派生类实例对象的地址,或者基类的引用变量引用派生类的实例,比如实例代码:

int main()
{
    Animal& c_animal = Cat();
    c_animal.eat();
    Animal* pAnimal = new Cat();
    pAnimal->sleep();
    return 0;
}

那么编译器是如何利用虚函数表指针与虚函数表实现多态?

派生类继承于基类,构造派生类时需要先构造基类,当构造含有虚函数的基类对象时,编译器将该对象的虚函数表指针指向基类的虚函数表,当构造派生类对象时,编译器会将该对象的虚函数表指针指指向派生类的虚函数表,而如果派生类中重写了基类的虚函数,那么派生类虚函数表中的函数地址就是派生类的函数地址,如果没有重写基类的虚函数,那么派生类虚函数表中的函数地址依然是基类的函数地址。而且构造派生类实例对象中只能有一个虚函数表指针,并且是在构造基类时就创建的。

那么,在运行时,基类的指针指向了派生类的实例对象地址,调用某个虚函数就需要在当前指向的对象的虚函数表中查找该虚函数地址,并调用该函数的的一些指令。

看一下虚函数表查询的过程:

Animal* pAnimal = new Cat();
pAnimal->sleep();

假设上面的 pAnimal 的类型是 Animal* ,则 pAnimal->sleep() 这条语句的过程是:

  1. 取出 pAnimal 的前 4 个字节(虚函数表指针成员,64 位下为 8 字节)。注:这个操作会取出虚函数表的地址,如果 pAnimal 指向的是类 Animal 的对象,则这个地址就是类 Animal 的虚函数表地址,如果是类 Cat 的对象,那么这个地址就是类 Cat 的虚函数表地址。
  2. 根据取到的虚函数表的地址找到虚函数表,在其中查找要调用的虚函数地址。可以认为虚函数表就是根据函数名作为索引进行查找,但是编译器肯定会使用更高效的查找方法。如果 pAnimal 指向的是类 Animal 的实例对象,自然就会在类 Animal 的实例对象中查出 Animal::sleep 的地址,若 pAnimal 指向的是类 Cat 的实例对象,自然就会在类 Cat 的实例对象中查出 Cat::sleep 的地址,若类 Cat 中没有自己的 sleep 函数,因此在类 Cat 虚函数表中保存的是 Animal::sleep,这样即使 pAnimal 指向的是类 Cat 的实例对象,也能在虚函数表中找到 Animal::sleep 的函数地址。
  3. 根据找到的虚函数地址调用该虚函数。

从上面的过程看到,如果通过基类指针或引用调用虚函数的语句,就一定是多态的,而且一定会执行上面的查表过程,哪怕这个虚函数仅在基类中有,而派生类中没有。

多态机制能够提高程序的开发效率,但是也增加了程序运行时的开销。其虚函数表,各个实例对象中包含的虚函数表的地址都是空间上的额外开销,而查虚函数表的过程则是时间上的额外开销。

在计算基发展的早期,计算机非常昂贵稀有,运行速度慢,计算的内存和时间是非常宝贵的,不惜多花人力编写运行速度更快,更节省内存的程序;如今,计算机的运行时间和内存没有人的时间宝贵,因此在可以接受的前提下,降低程序的运行效率而提升人员的开发效率是非常值得的。而“多态”就是一个典型的例子。

派生类中新增虚函数

上面的实例中,都是派生类继承基类并重写基类的虚函数,但是如果派生类不仅重写了基类的虚函数,而且派生类中有新增加了自己的虚函数,我们上文中说过,如果一个类中有虚函数,就会有虚函数表指针成员和虚函数表,那么这种情况下的内存布又是怎样呢?我们看以下如下程序:

class Animal
{
public:
    virtual void eat() { cout << "Animal::eat" << endl; }
    virtual void sleep() { cout << "Animal::sleep" << endl; }
    virtual void play() { cout << "Animal::play" << endl; }

private:
    string m_name;
    int m_age = 0;
};

class Cat : public Animal
{
public:
    virtual void eat() { cout << "Cat::eat" << endl; }
    virtual void sleep() { cout << "Cat::sleep" << endl; }
    virtual void drink() { cout << "Cat::attack" << endl; } //派生类中自己的虚函数
};

查看它的内存布局如下:

> cl /d1 reportSingleClassLayoutCat CppTest.cpp
class Cat       size(48):
        +---
 0      | +--- (base class Animal)
 0      | | {vfptr}
 8      | | ?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@ m_name
40      | | m_age
        | | <alignment member> (size=4)
        | +---
        +---

Cat::$vftable@:
        | &Cat_meta
        |  0
 0      | &Cat::eat
 1      | &Cat::sleep
 2      | &Animal::play
 3      | &Cat::drink

Cat::eat this adjustor: 0
Cat::sleep this adjustor: 0
Cat::drink this adjustor: 0

我们可以看到,派生类自己的虚函数还是在当前实例对象的虚函数表中,而且在基类或父派生类的虚函数后面,所以可以总结两点如下:

  1. 虚函数是按照其声明的顺序放在虚函数表中的。
  2. 基类的虚函数在派生类的虚函数前面。

多继承情况下的虚函数表

上面已经说明了单继承下多态于虚函数表的原理,以及派生类中新增了自己的虚函数的情况,再看看如果是多继承情况下,又有哪些差别。有如下实例程序:

class Animal
{
public:
    virtual void eat() { cout << "Animal::eat" << endl; }
    virtual void sleep() { cout << "Animal::sleep" << endl; }
    virtual void play() { cout << "Animal::play" << endl; }

private:
    string m_name;
    int m_age = 0;
};

class Action
{
public:
    virtual void eat() { cout << "Action::eat" << endl; } //Animal类中也有同名成员函数
    virtual void jump() { cout << "Action::jump" << endl; }
    virtual void attack() { cout << "Action::attack" << endl; }
    virtual void defend() { cout << "Action::defend" << endl; }
    
};

class Cat : public Animal, public Action
{
public:
    virtual void eat() { cout << "Cat::eat" << endl; }
    virtual void sleep() { cout << "Cat::sleep" << endl; }
    virtual void attack() { cout << "Cat::attack" << endl; }
    virtual void drink() { cout << "Cat::attack" << endl; } //派生类中自己的虚函数
};

我们看一下其内存布局:

> cl /d1 reportSingleClassLayoutCat CppTest.cpp
class Cat       size(56):
        +---
 0      | +--- (base class Animal)
 0      | | {vfptr}
 8      | | ?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@ m_name
40      | | m_age
        | | <alignment member> (size=4)
        | +---
48      | +--- (base class Action)
48      | | {vfptr}
        | +---
        +---

Cat::$vftable@Animal@:
        | &Cat_meta
        |  0
 0      | &Cat::eat
 1      | &Cat::sleep
 2      | &Animal::play
 3      | &Cat::drink

Cat::$vftable@Action@:
        | -48
 0      | &thunk: this-=48; goto Cat::eat
 1      | &Action::jump
 2      | &Cat::attack
 3      | &Action::defend

Cat::eat this adjustor: 0
Cat::sleep this adjustor: 0
Cat::attack this adjustor: 48
Cat::drink this adjustor: 0

其中,派生类中,我们不仅增加了属于自己的 drink() 虚函数,而且在两个基类中有个同名的 eat() 函数。从内存布局中我们可以看到:

  1. 每个基类都有自己对应的虚函数表
  2. 派生类类成员中新增的虚函数被放到了第一个基类的表中(其顺序是按继承时的顺序),这样做的目的是不同的基类类型指针指向同一个派生类实例,能够调用到实际的函数。
  3. 两个基类虚函数表中的虚函数 eat() 都被替换成派生类的函数指针了。

访问虚函数表

常规访问虚函数表

首先因为虚函数表存在于基类实例对象的地址的起始地址,我们只要取前 4 个字节(32 位下一个指针的大小,64 位为 8),然后再取地址,再取前 4 个字节,将其强转为函数指针类型就可以访问了,实例程序如下:

class Base
{
private:
    virtual void f() { cout << "Base::f" << endl; }
};

class Derive : public Base
{
};

typedef void (*Fun)(void);

void main()
{
    Derive d;
    Fun pFun = (Fun) * ((int *)*(int *)(&d) + 0);
    pFun();
}

通过基类类型指针访问派生类自己的虚函数

首先我们知道派生类类自己的虚函数是不能直接通过基类类型指针访问的,编译就不能通过,但是上面我们说过,派生类的实例对象中,派生类和基类的虚函数在一个虚函数表中,并且派生类的虚函数在基类的虚函数后面。但在运行时,我们可以通过指针的方式访问虚函数表来达到违反 C++ 语义的行为。

访问 non-public 的虚函数

如果基类的虚函数不是 public 的,但这些非 public 的虚函数同样会存在于需表中,所以通过上面的方式同样可以访问。

访问多重继承的虚函数表

多重继承下,因为虚函数表不止一个,所以访问时需要增加一个维度,更像是一个二维数组,其访问思想如下:

typedef void (*Fun)(void);
pFun = (Fun)*((int*)*(int*)((int*)&d+0)+0);
pFun = (Fun)*((int*)*(int*)((int*)&d+0)+1);

pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);

总体上访问思路还是和上面的类似。

参考:
C++ 虚函数表解析
C++虚函数表(多态的实现原理)

内联函数online的定义和作用 说明: 内联函数是一个小型函数,以牺牲空间来节省函数调用带来的额外开销,一般用以比较小函数或者使用频率很高的函数,函数内部内部没有复杂的语句,如开关语句switch,循环语句for等 定义: (1)在 C++ 中,可以在定义函数时,在返回值类型前面加上 inline 关键字 inline int max() { ...... return 0; } (二)直接在类的内部进行函数的声明和定义,则默认其是内联函数 class A { public: int max() { ...... ret 阅读详情

相关推荐

C++多态(五)---菱形继承中的虚函数表详解

C++多态 菱形继承 虚基表指针与虚基表 我们知道,在虚继承(菱形继承)中,对于类D创建的对象d,为了避免A类中的变量重复,所以,将A类中成员变量放在d对象模型的最下面,由B类与C类各自虚基表指针访问虚基表中偏移量的方式进行访问A类成员变量。 虚函数表指针与虚函数表(虚表) 在类中成员函数实现多态时,需要将成员函数定义为虚函数,所以,在多态的情景下,单继承下会存在一个虚函数表指针,指向成员函数...

董皓宇 3835

c++ - 虚函数表

1.什么是虚函数表 所谓虚函数表就是存放着当前类中所有虚函数地址的表。在实例化一个具有虚函数的类时,这个表 也被分配到这个实例对象的内存中,通过虚函数表可以指明所要调用的函数的位置。在C++编译器 中虚函数表的地址存放在对象的最前面,这是为了即使多继承下也能快速获取到虚函数表。 代码示例: class Base{ public: virtual void A(){cout << "Base::A()" << endl;} virtual void B(){cout &

weixin_49303682的博客 2821

9-4:C++多态之单继承和多继承中的虚函数表

文章目录(1)单继承中的虚函数表(2)多继承中的虚函数表 (1)单继承中的虚函数表 如下继承体系中,fun1函数重写,fun2未被重写,B类中fun3和fun4也被定义为了虚函数 #include <iostream> #include <stdio.h> using namespace std; class A { public: virtual void fun1() { cout << "fun(1)" << endl; } virtual

快乐江湖的博客 749

简述虚函数表

前段时间我在博客中简单地说了下C++的虚函数,所谓虚函数,就是C++实现多态性的方法。那么编译器是如何识别虚函数的呢?据百度百科描述,C++并未规定用何种方法实现虚函数,但是大部分编译器厂商都选择使用虚函数表这种方法,那到底什么是虚函数表??? 虚函数表,称为V-Table。虚函数表是一片连续的内存区域,每个内存单元存放着JMP指令地址。 看到这里,可能会比较懵逼,啥是内存单元,啥是JM...

wufeifan_learner的博客 6654

C++ 多态 虚函数 虚函数表 最是详细

高质量的C++多态讲解,详细讲解虚函数,虚函数表,虚函数继承,虚函数继承下的内存分配等

Win10 Rational Rose 安装教程

在此教程中我们需要四个文件,点此下载[提取码:ig33] 其中第一个为2007的安装包,第二个为破解文件 前言 很多小伙伴反应说会出现几天后就到期的问题,包括我也出现了该问题,如果你已在其他地方安装好了文件且破解成功,且但几天后到期,如果可以使用更改时间的方式打开,那么可以跳过接下来的教程,直接看第三节,我们采用批处理的形式一键完成从修改时间到打开最后改回来的方法解决此问题 一、安装软件 解压缩两个安装包,进入 Rational Rose文件夹 选择setup.exe开始安装 按照图示依次点击

CoderJiang 2万+

类的动态多态与虚函数表:C++中的动态多态与虚函数表

1.背景介绍 在C++中,动态多态是一种在编译期间无法确定调用哪个函数的机制,它通常与虚函数有关。虚函数表(vtable)是实现动态多态的关键数据结构。本文将详细介绍C++中的动态多态与虚函数表的核心概念、算法原理、最佳实践、应用场景和未来发展趋势。 1. 背景介绍 在C++中,类的多态性是指同一种类型的对象可以被多种不同的方式使用。动态多态是指在运行时根据对象的实际类型来确定调用哪个函数。...

AI天才研究院 715

【深度解析】信息素养提升实践活动(附:历年获奖作品分析)

全国师生信息素养提升实践活动是由教育部教育技术与资源发展中心(中央电化教育馆)主办,面向全国师生的一项信息化交流展示活动。

m0_74417957的博客 2628

【c++】多态&&虚函数&&抽象类&&继承中的虚函数表详解

【c++】多态&&虚函数&&抽象类&&继承中的虚函数表详解

m0_74722801的博客 1227

C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

本文借助easyx库函数(提供下载链接),很方便地用C语言实现了鼠标、按钮、进度条、坐标尺等操作,为普通C程序的友好人机交互界面提供了一种简单便捷的方案。

体会编程语言独到的美 17万+

Ubuntu22环境下Xinference与RAGFLOW集成:构建高效rerank模型服务【实战指南】

本文详细介绍了在Ubuntu22.04系统上,通过部署Xinference模型推理服务来加载bge-reranker-base等rerank模型,并将其与RAGFLOW框架集成的完整实战指南。该方案实现了模型服务的解耦与灵活管理,有效提升RAG系统的检索精度与答案相关性,并提供了从环境配置、服务启动、网络连接到性能调优及常见问题排查的全流程解决方案。

pluto的博客 500

【CPP】类与多态

例如典中典的火车票的例子,设计一个自助售票函数,设计一个父类为乘客,设计一个子类继承自父类为学生,再设计一个子类继承自父类为军人,每个种乘客类型可以买不同价格的票,当这类对象作为参数(传引用/指针)传进一个为父类"乘客"的自助售票函数中,根据函数判断生成符合当前乘客身份的票。覆写的概念很重要,从字面意思咱就知道,子类的情况可能会和父类不太一样,此时我们就可以覆写掉父类的方法,改成我们想让子类所呈现的模式,当然,这里的覆写在底层的角度上其实说不上是覆写,这个后面的小节会提到。

2302_79981653的博客 1343

集成电路模拟版图入门-版图基础学习笔记(四)

第三部分:版图的准备 2. 设计规则 3) Design Rule 2. 设计规则 4) 规则定义 4.1 NW(N WELL) 2. 设计规则 4) 规则定义 4.1 NW(N WELL) 2. 设计规则 4) 规则定义 4.2 PO(Poly) 2. 设计规则 4) 规则定义 4.3 M1(Metal1) 2. 设计规则 4) 规则定义 4.4 VIA 3. DRC文件 3.1 DRC:Design Rule Check,设计规则检查。 3.2 DRC程序了解有关

weixin_52955333的博客 6730

C++中的多态——理解虚函数表及多态实现原理

多态的概念,构成条件;虚函数的重写,重写的定义,重写的特殊情况,override和final关键字,区分重写、重载、重定义,抽象类的概念;多态的实现原理,父类对象模型,生成默认构造方法的场景,子类对象模型,多态的调用原理,多继承的虚函数表;继承与多态中的常见问题

qq_44631587的博客 2071

汇川AM系列ethercat控制伺服的使用说明(含转矩模式)

本文以一个实际例子,介绍ethercat伺服驱动器的工作原理,以及在汇川AM系列PLC中,如何点动、定位、速度、转矩控制ethercat伺服。

qq_34047402的博客 5111

帝企鹅优化器(EPO)详解:从基础原理到代码实战

帝企鹅优化器(EPO)是受帝企鹅群体在极寒环境中抱团取暖行为启发,于2018年提出的一种群体智能优化算法。其核心机制是模拟帝企鹅种群通过动态调整位置来维持体温的过程,主要包括确定集群边界、计算温度分布、衡量个体间距离以及更新位置四个步骤,从而在求解复杂优化问题时有效平衡全局探索与局部开发。该算法具有参数少、结构清晰、易于实现等优点,在工程优化、图像处理、机器学习特征选择以及冷链物流车辆路径规划等领域展现出良好的应用潜力。

qq_42212808的博客 139

【C++进阶之路】第二篇:多态 & 抽象类 & 单继承和多继承关系中的虚函数表

多态的概念,多态的构成条件,虚函数重写,C++11final和overrid,重载、重写、隐藏的对比,抽象类,虚函数表,多态原理,动静态绑定,单多继承下的虚函数表理解,继承和多态常见面试题

Captain_ldx的博客 778

无法将“choco”项识别为 cmdlet、函数、脚本文件或可运行程序的名称的解决方案

本文主要介绍了无法将“choco”项识别为 cmdlet、函数、脚本文件或可运行程序的名称的解决方案,希望能对使用wIndows的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 12万+

C++ 中的虚函数、虚函数表、虚函数表指针、运行时多态(动态多态)、动态绑定

a. 定义:在 C++ 中,被。

m0_53601985的博客 2237

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

[C++] 多态类中的虚函数表和虚函数表指针

C++中多态类中的虚函数表和虚函数表指针建立时间 答:1. 虚函数表在编译期建立,虚函数的地址存放于虚函数表之中        2.虚函数表指针在运行期建立,也就是构造函数被调用时进行初始化的 C++虚函数表和虚函数表指针与类和对象的关系 如果一个类中含有虚函数,那么其虚函数表和虚函数指针的归属和存储位置如下所示 类 对象 存储位置 ...

weixin_44922845的博客 696

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++之多态总结(多态的定义及实现,抽象类,多态原理,单继承,多继承中的虚函数表)

C++中多态相关知识1.多态的概念2.多态的定义及实现3.抽象类4.多态的的原理5.单继承和多继承关系中的虚函数表6.继承和多态常见的面试问题 1.多态的概念 2.多态的定义及实现 3.抽象类 4.多态的的原理 5.单继承和多继承关系中的虚函数表 6.继承和多态常见的面试问题 ...

今天你AC了吗 942

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【C/C++ 多态中的虚函数的虚函数表】详细的了解一下吧(要先知道有虚函数表

多态是面向对象程序设计中的一个重要特性,它允许不同类的对象对同一消息作出响应。在C++中,多态的实现主要依赖于虚函数和虚函数表。以下是对多态中虚函数表的详细描述:虚函数表(Virtual Function Table,简称VTable)是C++中用于支持多态性的一个关键机制。当一个类中包含虚函数时,编译器会为该类生成一个虚函数表,该表包含了指向类中所有虚函数的指针。每个包含虚函数的类的对象都会包含一个指向其所属类的虚函数表的指针(通常称为vptr)。虚函数表的主要作用是支持多态性。通过虚函数表,基类指针或引

一起学习进步! 1429

C++虚函数和虚函数表原理,多态中的重写!

虚函数的地址存放于虚函数表之中。运行期多态就是通过虚函数和虚函数表实现的。 类的对象内部会有指向类内部的虚表地址的指针。通过这个指针调用虚函数。 虚函数的调用会被编译器转换为对虚函数表的访问: ptr->f(); //ptr代表this指针,f是虚函数 *(ptr->vptr[1])(ptr); 上述代码中,ptr代表一个this指针,ptr指向的vptr是类内部的虚表指针。这个虚表指针会被放在类的最前方(VS2017),1就是虚函数指针在虚函数表中的索引值。在这个索引值表示的虚表的槽中存放

qq_44985337的博客 453

C++中的多态 -- 多态的概念,多态的构成条件,虚函数,override和final关键字,重载/重写/隐藏的对比,纯虚函数和抽象类,多态的原理,虚函数表指针,虚函数表

本文系统介绍了C++多态的核心概念与实现原理。主要内容包括:1)多态分为编译时多态(函数重载/模板)和运行时多态(虚函数机制);2)实现运行时多态需要满足:基类指针/引用调用虚函数、派生类重写虚函数;3)虚函数表机制:类对象包含虚表指针指向虚函数地址数组,多态调用时通过虚表动态绑定;4)特殊语法:协变返回值、虚析构函数、override/final关键字;5)纯虚函数与抽象类。通过内存模型分析揭示了虚函数表的存在及其在代码段的存储位置,并对比了静态绑定与动态绑定的区别。全文通过丰富代码示例详细阐述了多态的实

CSQCSQCC的博客 1628

【C++】多态

C++多态众多知识点的讲解,多态的概念、多态的定义及实现、虚函数、虚函数的重写、多态的调用、虚构函数的重写、析构函数的重写、override、final、抽象类、接口继承与实现继承、多态的原理、虚函数表、多态的调用、动态绑定与静态绑定、单继承和多继承的关系、多继承中的虚函数表、菱形继承、菱形虚拟继承、多态知识点总结、多态常见面试题、笔试题。

Brant_zero的博客 1063
上一篇: 使用VS查看类实例的内存布局
下一篇: C++虚继承中的虚基类表
code_peak
博客等级 码龄5年 403粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code_peak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值