虚函数表 以及 虚函数表的继承过程

article/2025/10/4 4:11:16

目录

一、虚函数表 和 虚表继承

1、虚函数表

2、虚表继承

(1) 子类未重写父类虚函数

(2) 子类重写了父类虚函数

二、虚表的特点

1、同一个类的对象的虚表指针相同

2、多继承时子类中的两个父类虚表地址不一样(实际调用是同一个函数)

三、虚表指针和虚函数放在哪??


下面介绍时搭配使用的案例代码如下:

class Person {
public:virtual void BuyTicket() { cout << "Person类:买票-全价" << endl; }
};class Student : public Person {
public:// 子类的 virtual 可以不写,但是父类的必须写virtual void BuyTicket() { cout << "Student类:买票-半价" << endl; }
};// 售票窗口
void TicketWindow(Person& p)
{ p.BuyTicket(); 
}int main(){Person ps;Student st;TicketWindow(ps);    // 传递Person对象买成人票TicketWindow(st);    // 传递Student对象买半票
}

一、虚函数表 和 虚表继承

1、虚函数表

当子类的某个成员函数是虚函数时,此时子类对象所在空间中,除了已经声明的子类成员外,会多出一个成员,那就是 虚函数表指针_vfptr(简称“虚表指针”),在构造函数初始化阶段才会初始化该虚表指针。虚表指向一个虚函数表,虚函数表中存放了虚函数的地址。(严格来说,这里的虚表指针不是虚函数表的地址,但是为了方便理解,先暂时这样介绍

2、虚表继承

在继承的时候,虚表指针也会被继承。这样的话,就分为了两种情况,一种是子类没有重写父类的虚函数,一种是子类重写了父类的虚函数。

(1) 子类未重写父类虚函数

在解释之前,我们先使用VS中的监视窗口了解,先把上面Student类中的虚函数注释掉。

class Student : public Person {
public://virtual void BuyTicket() { cout << "Student类:买票-半价" << endl; }
};

我们会发现虚函数的地址相同,但是虚函数表的地址不同。这是因为,子类原模原样地继承了父类的虚表指针指向的虚函数,这就是 “虚函数地址是相同的” 的原因;(虚函数表的地址不同,是因为虚表指针本质上是某一句汇编指令的地址,不同类的对象因为最后要调用不同的虚函数,所以执行的指令肯定也不同)

(2) 子类重写了父类虚函数

下面我们同样使用监视窗口来观察。

class Student : public Person {
public:virtual void BuyTicket() { cout << "Student类:买票-半价" << endl; }
};

在继承的时候,在代码区产生了新的函数。子类重写了父类虚函数的代码,虽然依然会继承父类的虚表指针,但是虚函数表里写的虚函数地址就不再是父类的虚函数地址了,而是重写以后新的虚函数地址。

二、虚表的特点

1、同一个类的对象的虚表指针相同

假设现在有两个Person 类的对象 ps1 和 ps2 。

int main() {Person ps1;Person ps2;return 0;
}

通过监视窗口就会发现,同一个类的对象的虚表指针是相同的。其实上面也提到,虚表指针 __vfptr本质上是 某一句汇编指令的地址,不同类的对象因为要调用不同的虚函数,所以执行的指令肯定是不同的,但是同一个对象调用的虚函数是一样的,所以执行相同的指令,即虚表指针是一样的。

2、多继承时子类中的两个父类虚表地址不一样(实际调用是同一个函数)

我们再新加一个 Teacher 类,然后让Student 类先后继承Person类和Teacher类,然后通过监视窗口看一下Student类的虚表继承情况。

class Teacher {
public:virtual void BuyTicket() { cout << "Teacher类:买票-优惠价" << endl; }
};class Student : public Person, public Teacher {
public:virtual void BuyTicket() { cout << "Student类:买票-半价" << endl; }
};

监视窗口的情况如下:

你或许会觉得很奇怪,子类明明重写了父类的虚函数,此时应该换上子类的虚函数地址,也就是说,Person下的虚函数地址 和 Teacher 下的虚函数地址应该是一样的才对。为什么会不一样?

==》其实是一样的,只不过Teacher类在被继承的时候,需要多执行其他的指令,所以这里填的是多执行的指令的地址,实际在调用的时候,会被替换成 和Person 一样的虚函数地址。

三、虚表指针和虚函数放在哪??

虚表指针__vfptr 是对象的一部分,对象在哪,虚表指针就在哪,所以虚表指针在栈上。

因为同一个类的对象指向的是同一个虚函数表,所以虚函数不能因为对象被销毁就被释放了,所以虚函数放在了代码区。(严格来说是在常量区,只不过常量区和代码区被合并了)


http://chatgpt.dhexx.cn/article/OCejRN2e.shtml

相关文章

C++虚函数和虚函数表原理

虚函数的地址存放于虚函数表之中。运行期多态就是通过虚函数和虚函数表实现的。 类的对象内部会有指向类内部的虚表地址的指针。通过这个指针调用虚函数。 虚函数的调用会被编译器转换为对虚函数表的访问&#xff1a; ptr->f(); //ptr代表this指针&#xff0c;f是虚函数…

虚函数 虚函数表

虚函数是面向对象编程函数的一种特定形态&#xff0c;是C用于实现多态的一种有效机制。C的多态可以分为静态多态和动态多态。函数重载和运算符重载实现的多态属于静态多态&#xff0c;而通过虚函数可以实现动态多态。实现函数的动态联编其本质核心则是虚表指针与虚函数表。 虚…

虚函数表和虚表指针

1&#xff0c;虚函数的含义 用virtual声明类的成员函数称之为虚函数 2&#xff0c;作用 用于实现多态 存在继承关系&#xff0c;子类继承父类子类重写了父类的virtual function子类以父类的指针或者引用的身份出现 3&#xff0c;虚函数的实现原理 其中的关键就是两点&#xf…

C++ 虚函数和虚函数表

一、虚函数 1.虚函数的概念 1.虚函数就是在基类中被关键字 virtual 说明&#xff0c;并在派生类中重新定义的函数。 2.虚函数的作用是允许在派生类中重新定义与基类同名的函数&#xff0c;并且可以通过基类指针或引用来访问基类和派生类中的同名函数。 3.虚函数的定义是在基类…

C++虚函数表剖析

关键词&#xff1a;虚函数&#xff0c;虚表&#xff0c;虚表指针&#xff0c;动态绑定&#xff0c;多态 一、概述 为了实现 C 的多态&#xff0c;C 使用了一种动态绑定的技术。这个技术的核心是虚函数表&#xff08;下文简称虚表&#xff09;。本文介绍虚函数表是如何实现动态…

C++ 虚函数表解析

C 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C中的虚函数的作用主要是实现了多态的机制。关于多态&#xff0c;简而言之就是用父类型别的指针指向其子类的实例&#xff0c;然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”&#x…

虚函数表详解

关键词&#xff1a;虚函数&#xff0c;虚表&#xff0c;虚表指针&#xff0c;动态绑定&#xff0c;多态 一、概述 为了实现C的多态&#xff0c;C使用了一种动态绑定的技术。这个技术的核心是虚函数表&#xff08;下文简称虚表&#xff09;。本文介绍虚函数表是如何实现动态绑定…

虚函数及虚函数表

虚函数及虚函数表 各个类对象共享类的虚函数表&#xff0c;每个类对象有个虚函数指针vptr&#xff0c;虚函数指针vptr指向虚函数表&#xff08;对于只有一个虚函数表的情况&#xff09;。 虚函数 简单的说&#xff0c;每一个含有虚函数&#xff08;无论是其本身的&#xff0…

简述虚函数表

前段时间我在博客中简单地说了下C的虚函数&#xff0c;所谓虚函数&#xff0c;就是C实现多态性的方法。那么编译器是如何识别虚函数的呢&#xff1f;据百度百科描述&#xff0c;C并未规定用何种方法实现虚函数&#xff0c;但是大部分编译器厂商都选择使用虚函数表这种方法&…

虚函数表的问题

虚函数表&#xff1a; 多态是由虚函数实现的&#xff0c;而虚函数主要是通过虚函数表&#xff08;V-Table&#xff09;来实现的。 如果一个类中包含虚函数&#xff08;virtual修饰的函数&#xff09;&#xff0c;那么这个类就会包含一张虚函数表&#xff0c;虚函数表存储的每…

虚函数表详解及其应用场景

目录 概述1. 虚函数表概述2. 虚函数表的实现原理2.1. 虚函数的声明和定义2.2. 虚函数表的创建和初始化2.3. 虚函数调用的过程 3. 虚函数表的应用场景3.1. 多态性3.2. 基类指针和引用的使用3.3. 动态绑定3.4. 接口定义 结论 概述 在面向对象编程中&#xff0c;虚函数表&#xf…

C++ 面试必问:深入理解虚函数表

点击蓝字 关注我们 深入理解C 虚函数表 C中的虚函数的作用主要是实现了多态的机制。关于多态&#xff0c;简而言之就是用父类型别的指针指向其子类的实例&#xff0c;然后通过父类的指针调用实际子类的成员函数。 Derive d; Base1 *b1 &d; Base2 *b2 &d; Base3 *b3 …

C++ 虚函数表

C类在内存中的存储方式 C 内存分为 5 个区域&#xff1a; 堆 heap &#xff1a;由 new 分配的内存块&#xff0c;其释放编译器不去管&#xff0c;由程序员自己控制。如果程序员没有释放掉&#xff0c;在程序结束时系统会自动回收。涉及的问题&#xff1a;“缓冲区溢出”、“内…

ThinkPHP3.2.2获取数据列getField()优化

getField()是一个常用方法&#xff0c;我习惯用来获取带key的数组&#xff0c;方便数据整合。 使用第1个参数&#xff0c;传入一个字段名&#xff0c;获取某一个数据值&#xff0c;返回满足条件的数据表中的该字段的第一行的值&#xff1a; $id M("User")->getFi…

java class getfield_java.lang.Class.getField()方法实例

全屏 java.lang.Class.getField() 返回一个Field对象&#xff0c;它反映此Class对象所表示的类或接口的指定公共成员字段。 name参数是一个字符串&#xff0c;指定所需字段的简单名称。 声明 以下是java.lang.Class.getField()方法的声明public Field getField(String name) th…

java getfield_Java 反射:通过 getField() 设置公共全局变量

Java 通过 getField() 操作公共全局变量 以前写 JavaWeb 项目启动初始化系统配置全局变量的代码&#xff0c;都是 variable Properties.getProperty(name) 这样一行一行代码的设置&#xff0c;变量少还好说&#xff0c;变量一多真的很磨叽。所以一直想通过 循环 简化代码&…

getField和getDeclaredField的区别

这两个方法都是用于获取字段 1.getField 只能获取public的&#xff0c;包括从父类继承来的字段。 2.getDeclaredField 可以获取本类所有的字段&#xff0c;包括private的&#xff0c;但是不能获取继承来的字段。 (注&#xff1a; 这里只能获取到private的字段&#xff0c;但并不…

vscode插件开发总结

一、关于vscode插件 相信大家对vscode应该都不陌生&#xff0c;VSCode是微软出的一款轻量级代码编辑器&#xff0c;免费而且功能强大&#xff0c;以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐&#xff0c;对JavaScript和NodeJS的支持非常好&#xff0c;自带…

2021-前端-VsCode插件

此乃吾习前端&#xff0c;VsCode之插件&#xff0c;个人所装&#xff0c;喜着自拿&#xff0c;不足之处还望海涵&#xff0c;多加批评。 1.Auto Close Tag——自动闭合尾部的标签 2.Atuo Rename Tag——修改 html 标签 自动帮你完成头部和尾部闭合标签的同步修改 3.Bracket…

关于VSCode插件的安装位置

VSCode的插件地址修改_上善若泪-CSDN博客_vscode插件位置文章目录1 data文件夹2 使用--extensions-dir命令3 使用mklink命令vscode编辑器强大的地方是可以使用各种各样的插件&#xff0c;但是插件默认的地方是在:C盘&#xff0c;让一些强迫症可能会受不了&#xff0c;非要迁移到…