C++中的虚函数表

article/2025/10/4 4:14:12

引言:

多态对于C++这种面向对象的语言来讲,其重要性是不言而喻的,用了足足半天的时间来把我所理解的多态表达出来,其中还有很多细节需要以后补充。(一个字一个字写,还要画图,太累了)

面试中遇到最多的问题就是多态的概念,以及多态的实现依据,首先多态发生的条件:
(1)必须要有子类继承父类

(2)父类中存在虚函数,并且子类重写该虚函数

(3)父类的指针或者引用指向子类对象

这三个条件缺一不可。那么多态究竟是怎么实现的呢?那就不得不提到虚函数表,在每一个实例化的子类对象的头部,首先是一个指向虚函数表的指针,那么虚函数表中依次存放着父类的方法和子类特有的方法,如果子类重写父类的方法,那么就会替换父类的方法,否则的话就照抄。下面给出一个示意图。

这里,Base是一个基类,里面有三个虚函数f,g,h。子类son继承Base,实例化一个子类对象b,因为我们知道,虚函数指针(也就是指向虚函数表的指针),是存放在类对象的头部的,所以对b取地址,其实得到的就是虚函数指针的地址,虚函数指针又指向虚函数表,那么你对&b解引用,自然也就得到了虚函数表的首地址(也就是第一个虚函数的地址),虚函数表里依次存放了虚函数的地址,其中,存放的顺序:父类中的函数(如果有重写,就直接覆盖)、子类中特有的函数。

 这里面需要注意的是,虚函数表并不是共享的,父类和子类都会有自己的虚函数表,可以通过分别取各自的虚函数表地址来验证。

 我们可以进一步来验证一下每个类对象的头部存放的都是指向虚函数表地址的指针这一事实。

首先给出父类和子类


class Base
{
public:virtual void f() { cout << "调用base::f" << endl; }virtual void g() { cout << "调用base::g" << endl; }virtual void h() { cout << "调用base::h" << endl; }};
class son:public Base
{
public:void f() { cout << "调用son::f" << endl; }void f1() { cout << "调用son::f1" << endl; }
};

实例化一个子类对象,并且获得其虚函数表的地址。

typedef void(*Fun)(void);Base b;Fun pFun = NULL;cout << "虚函数指针的地址:" << (int*)*(int*)(&b) << endl;

进一步,获得虚函数表的地址

cout << "虚函数表 —(虚函数第一个函数地址:)" << (int*)*(int*)*(int*)(&b) << endl;pFun = (Fun)*((int*)*(int*)(&b));pFun();

如果是一个类继承了多个基类,那么它的虚函数表应是如下情况

 

 下面有几个问题 需要解决一下:

Q1:  为什么父类指针可以指向子类对象?

可以通俗的理解,子类可能含有一些父类没有的成员变量或者方法函数,但是子类肯定继承了父类所有的成员变量和方法函数。所以用父类指针指向子类时,没有问题,因为父类有的,子类都有,不会出现非法访问问题。但是如果用子类指针指向父类的话,一旦访问子类特有的方法函数或者成员变量,就会出现非法。虽然父类指针可以指向子类,但是其访问范围还是仅仅局限于父类本身有的数据,那些子类的数据,父类指针是无法访问的。

Q2:  为什么非要用父类指针指向子类对象,才能调用子类对应的虚函数?

首先,因为子类包含有父类,把子指针赋给父指针时其实只是把子类中父类部分的地址赋给了父类指针而已,(而父类里没有包含子类,自然不能进行复制。)这个时候再用这个指针去调用父类和子类共有的函数,其实调用的是子类重写之后的虚函数) //这个理解真的很棒,参考别人的。

如果一个类继承了多个类,而且同时重写了各个类的虚函数,那么此时如果你只是单纯的想要用子类去调用虚函数,那么到底是调用的哪个父类的虚函数呢?这个时候用类的指针去指向子类对象就显得尤为重要了,此时才会调用到一个确定的父类的虚函数。

但是父类指针指向子类对象时不能调用子类特有的方法。

    son s;Base* b = &s;b->f();b->f1(); //f1为子类特有方法,此时报错


http://chatgpt.dhexx.cn/article/395whVm4.shtml

相关文章

虚函数原理与虚函数表

目录 一、 虚函数 二、虚函数原理与虚函数表 一、 虚函数 虚函数&#xff1a; 使用 virtual 关键字声明的函数&#xff0c;是动态多态实现的基础。 非类的成员函数不能定义为虚函数。 类的静态成员函数不能定义为虚函数。 构造函数不能定义为虚函数&#xff0c;但可以将析构函…

c++虚函数和虚函数表

什么是虚函数? 用virtual 修饰的成员函数叫虚函数 没有虚构造函数 不写虚函数&#xff0c;没有默认的虚函数 虚函数对于类的影响&#xff1a;增加一个指针的内存 虚函数的存储&#xff1a;虚函数表(了解内容&#xff1a;就是一个指针存储所有虚函数的首地址[函数指…

虚函数表存储位置

前言 先说结论&#xff1a;虚函数表存储在只读数据段&#xff08;.rodata&#xff09;、虚函数存储在代码段&#xff08;.text&#xff09;、虚表指针的存储的位置与对象存储的位置相同&#xff0c;可能在栈、也可能在堆或数据段等。 相信大家知道虚表指针和虚函数存储的位置…

C++虚函数表详解

C的虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中&#xff0c;主要是一个类的虚函数的地址表&#xff0c;这张表解决了继承、覆盖(override)的问题&#xff0c;保证其能真实的反应实际的函数。这样&#xff0c;在有虚函数的类…

【虚函数指针 虚函数表】

文章目录 虚函数指针和虚函数表1.虚函数的含义2.虚函数的作用3.虚函数的实现原理 多态的实现原理普通类当类中存在虚函数子类继承父类不重写虚函数子类继承父类重写虚函数 1.虚函数表指针2.虚函数表 虚函数指针和虚函数表 1.虚函数的含义 只有用virtual声明类的成员函数&…

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

目录 一、虚函数表 和 虚表继承 1、虚函数表 2、虚表继承 (1) 子类未重写父类虚函数 (2) 子类重写了父类虚函数 二、虚表的特点 1、同一个类的对象的虚表指针相同 2、多继承时子类中的两个父类虚表地址不一样&#xff08;实际调用是同一个函数&#xff09; 三、虚表指…

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…