C++虚函数和虚函数表
在上面的博文中描述了基类中存在虚函数时,基类和派生类中虚函数表的结构。
在派生类也定义了虚函数时,函数表又是怎样的结构呢?
先看下面的示例代码:
#include <iostream> using namespace std; class A
{
public:
virtual void funcA(){ cout<<"A"<<endl; }
}; class B
{
public:
virtual void funcB(){ cout<<"B"<<endl; }
}; class C : public A, public B
{
public:
virtual void funcC(){ cout<<"C"<<endl; }
}; int main()
{
C c;
cin.get();
}
class A 和 class B 都有一个虚函数,然后 class C 继承 A 和 B。在VS2010中,查看变量:

如图所示,局部变量中只显示了从 A 和 B 继承来的虚函数表地址。那么 C 自己的虚函数呢?
首先查看 A 虚函数表地址:

可以看到,虚函数表中的前4个字节就是 A 中虚函数的地址(红色框)。同时后面又紧跟着4个有内容的字节,然后才是表示虚函数表结束的4个0。
可以猜测,这应该就是 C 的虚函数地址。再来看一下 B 的虚函数表:

可以看到,虚函数表中只有 B 的虚函数这一个地址。为了证实上面的猜测,将函数指针从 A::funcA 向后递增一次,应该就是对 C::funC的调用:
int main()
{
typedef void(*pfun)(); C c;
auto p = &c; auto funcA = (pfun)**((int**)p);
funcA(); // 调用 A::funcA auto funcC = (pfun)*(*((int**)p) + );
funcC(); // 调用 C::funcC cin.get();
}
输出结果:
证实了我们的猜测。
如果在增加一个 class D 继承 C 呢?
class D : public C
{
virtual void funcD() {}
}; int main()
{
D d; cin.get();
}
变量:

和 C 中展示的一样,只有两个虚函数表。
内存:

可以看到,在 A::funcA 后还有两个地址,可以推测就是 C::funcC 和 D::funcD 的地址了。
总结:
1、在多继承中,派生类的虚函数表的个数由它所继承的“顶层的”基类的个数决定:有多少个这样的基类,就有多少个虚函数表。
2、派生类自己的虚函数被追加到第一个虚函数表的后面。
例如下面的继承:

假设每个类 X 都有一个 funcX 虚函数,那么G中虚函数和虚函数表如下:

C++虚函数和虚函数表的更多相关文章
- C++虚函数及虚函数表解析
一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Functio ...
- C++ 由虚基类 虚继承 虚函数 到 虚函数表
//虚基类:一个类可以在一个类族中既被用作虚基类,也被用作非虚基类. class Base1{ public: Base1(){cout<<"Construct Base1!&q ...
- 20140321 sizeof 虚函数与虚函数表 静态数组空间 动态数组空间 位字段
1.静态的数组空间char a[10];sizeof 不能用于1:函数类型 2:动态的数组空间new3:位字段 函数类型:int fun();sizeof(fun())计算的是返回类型的大小,并不是函 ...
- c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
- 为何JAVA虚函数(虚方法)会造成父类可以"访问"子类的假象?
首先,来看一个简单的JAVA类,Base. 1 public class Base { 2 String str = "Base string"; 3 protected vo ...
- C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构
一.基类指针.派生类指针 父类指针可以new一个子类对象 二.虚函数 有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数? 有解决方案,这个对象指针必须是一个父类类型 ...
- virtual之虚函数,虚继承
当类中包含虚函数时,则该类每个对象中在内存分配中除去数据外还包含了一个虚函数表指针(vfptr),指向虚函数表(vftable),虚函数表中存放了该类包含的虚函数的地址. 当子类通过虚继承的方式从父类 ...
- C++纯虚函数、虚函数、实函数、抽象类,重载、重写、重定义
首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不 ...
- 虚函数&纯虚函数&抽象类&虚继承
C++ 虚函数&纯虚函数&抽象类&接口&虚基类 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过 ...
随机推荐
- SendInput模拟键盘输入的问题
SendInput模拟键盘输入的问题 http://www.cnblogs.com/yedaoq/archive/2010/12/30/1922305.html 最近接触到这个函数,因此了解了一下, ...
- Ubuntu16.04安装Samba
在新装的ubuntu16.04下安装samba. 安装好samba后备份下配置文件: zhuben@zb:~$ sudo apt-get install samba zhuben@zb:~$ cd / ...
- 高德地图JavaScript开发
项目需求:标注一个或者两个点.显示信息窗体.自定义icon <!DOCTYPE html> <html lang="en"> <head> &l ...
- spring 声明式事务管理
简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...
- 加速编码的 JavaScript 库和工具
JavaScript库是 一个提前写好的JavaScript文件库,它可以很容易的开发基于JavaScript的应用,特别是AJAX和一些其它的以web为中心的技术.运用JavaScript最基本的方 ...
- Repeart控件使用
对于刚刚接触到repearter控件,了解不深,现做个记录方便以后的查看 <asp:Repeater ID="rpt_OrderList" runat="serve ...
- Asp.net的request类
ASP.NET获取客户端信息,暂时就这几个,有待添加~~ 1. 在ASP.NET中专用属性: 获取服务器电脑名:Page.Server.ManchineName 获取用户信息:Page.User 获取 ...
- 媒体查询使用方法@media
Media Queries能在不同的条件下使用不同的样式,使页面在不同在终端设备下达到不同的渲染效果.前面简单的介绍了Media Queries如何引用到项目中,但Media Queries有其自己的 ...
- 引用、引用和术语定义<abbr><acronym><address><bdo><blockquote><q><cite><dfn>
<abbr>-缩写 <acronym>-首字母缩写 <address>-地址 <bdo>-文字方向 <blockquote>-长的引用 & ...
- Asp.net MVC3表格共用分页功能
在建立的mvc3项目中,在Razor(CSHTML)视图引擎下,数据会在表格中自动的生成,但分页没有好的控件实现,这里我们开发了设计了一个分页的模板,适合于没有数据提交和有数据提交的分页的分页. 第一 ...