上次研究的是单继承的情况,这次研究多重继承下的虚函数表的排列情况。

这次A,A1,A2,B这几个类的继承关系如下图:

测试代码如下:

#include<iostream>
using namespace std; class A
{
public:
virtual void fun1()
{
cout<<"A::fun1"<<endl;
}
virtual void fun2()
{
cout<<"A::fun2"<<endl;
} virtual void fun3()
{
cout<<"A::fun3"<<endl;
} }; class A1:public A
{
public:
virtual void fun1()
{
cout<<"A1::fun1"<<endl;
} }; class A2:public A
{
public:
virtual void fun2()
{
cout<<"A2::fun2"<<endl;
}
virtual void fun3()
{
cout<<"A2::fun3"<<endl;
}
}; class B :public A1,public A2
{
public:
virtual void fun4()
{
cout<<"B::fun4"<<endl;
}
}; typedef void (*Fun)(void);
int main(int argc, char* argv[])
{
A1 a1; cout<<"A1虚函数表的地址为:"<<(int *)(&a1)<<endl; cout<<"A1第一个虚函数的地址为:"<<(int *) *(int *)(&a1)<<endl; Fun fun1,fun2,fun3,fun4; fun1=( Fun) ( *(int *) *(int *)(&a1));
fun1(); fun2=(Fun) (* ((int *) *(int *)(&a1)+1));
fun2(); fun3=(Fun) (* ((int *) *(int *)(&a1)+2));
fun3(); A2 a2; cout<<"A2虚函数表的地址为:"<<(int *)(&a2)<<endl;
cout<<"A2第一个虚函数的地址为:"<<(int *) *(int *)(&a2)<<endl; fun1=( Fun) ( *(int *) *(int *)(&a2));
fun1(); fun2=(Fun) (* ((int *) *(int *)(&a2)+1));
fun2(); fun3=(Fun) (* ((int *) *(int *)(&a2)+2));
fun3(); B b;
cout<<"B的第一个虚函数表的地址为:"<<(int *)(&b)<<endl;
cout<<"B的第一个虚函数表的第一个虚函数的地址为:"<<(int *) *(int *)(&b)<<endl; fun1=( Fun) ( *(int *) *(int *)(&b));
fun1(); fun2=(Fun) (* ((int *) *(int *)(&b)+1));
fun2(); fun3=(Fun) (* ((int *) *(int *)(&b)+2));
fun3(); fun4=(Fun) (* ((int *) *(int *)(&b)+3));
fun4(); cout<<"B的第二个虚函数表的地址为:"<<(int *)(&b)+1<<endl;
cout<<"B的第二个虚函数表的第一个虚函数的地址为:"<<(int *) *((int *)(&b)+1)<<endl; fun1=( Fun) ( *(int *) *((int *)(&b)+1));
fun1(); fun2=(Fun) (* ((int *) *((int *)(&b)+1)+1));
fun2(); fun3=(Fun) (* ((int *) *((int *)(&b)+1)+2));
fun3();
return 0;
}

运行结果:

A1虚函数表的地址为:0xbfb2e9ec
A1第一个虚函数的地址为:0x8048ff0
A1::fun1
A::fun2
A::fun3
A2虚函数表的地址为:0xbfb2e9d8
A2第一个虚函数的地址为:0x8048fd8
A::fun1
A2::fun2
A2::fun3
B的第一个虚函数表的地址为:0xbfb2e9d0
B的第一个虚函数表的第一个虚函数的地址为:0x8048fa8
A1::fun1
A::fun2
A::fun3
B::fun4
B的第二个虚函数表的地址为:0xbfb2e9d4
B的第二个虚函数表的第一个虚函数的地址为:0x8048fc0
A::fun1
A2::fun2
A2::fun3

具体说下B的情况,b分别从A1,A2继承了两个虚函数表,这两个虚函数表也是在对象的开始按照顺序开始排列,先是A1的虚函数表,然后是A2的虚函数表。

B的第一个虚函数表:(int *)(&b)

B的第一个虚函数表的第一个元素fun1=  * ((int *)  * (int *)(&b))

B的第一个虚函数表的第二个元素fun2=  * ((int *)  * (int *)(&b)+1)

......

B的第二个虚函数表:(int *)(&b)+1

B的第二个虚函数表的第一个元素 fun1=   * ((int *) *((int *)(&b)+1)+0)

B的第二个虚函数表的第二个元素 fun2=  * ((int *) *((int *)(&b)+1)+1)

结果画成虚函数表如下:

A的虚函数表图:

A1的虚函数表图:

A2的虚函数表图:

B的虚函数表图:

结论:

多重继承会有多个虚函数表,几重继承,就会有几个虚函数表。这些表按照派生的顺序依次排列,如果子类改写了父类的虚函数,那么就会用子类自己的虚函数覆盖虚函数表的相应的位置,如果子类有新的虚函数,那么就添加到第一个虚函数表的末尾。

注意:这里由于类A1和A2都只有指向虚函数表的指针,所以对于类B而言,这两个指针连续。如果A1有个成员的为int类型,则B的第二个虚函数表:(int *)(&b)+2,例如:

#include<iostream>
using namespace std; class Base1
{
public:
Base1(int num):num_1(num){}
virtual void foo1() { cout << "Base1:: foo1" << num_1 << endl;}
virtual void foo2() { cout << "Base1:: foo2" << num_1 << endl;}
virtual void foo3() { cout << "Base1:: foo3" << num_1 << endl;}
private:
int num_1;
}; class Base2
{
public:
Base2(int num):num_2(num){}
virtual void foo1() { cout << "Base2:: foo1" << num_2 << endl;}
virtual void foo2() { cout << "Base2:: foo2" << num_2 << endl;}
virtual void foo3() { cout << "Base2:: foo3" << num_2 << endl;}
private:
int num_2;
}; class Base3
{
public:
Base3(int num):num_3(num){}
virtual void foo1() { cout << "Base3:: foo1" << num_3 << endl;}
virtual void foo2() { cout << "Base3:: foo2" << num_3 << endl;}
virtual void foo3() { cout << "Base3:: foo3" << num_3 << endl;}
private:
int num_3;
}; class Derived1:public Base1
{
public:
Derived1(int num):Base1(num){}
virtual void faa1(){ cout << "Dervied1::faa1" <<endl;}
virtual void faa2() { cout << "Dervied1::faa2" <<endl;}
}; class Derived2:public Base1
{
public:
Derived2(int num):Base1(num){}
virtual void foo2(){ cout << "Dervied2::foo2" << endl;}
virtual void fbb2(){ cout << "Dervied2::fbb2" << endl;}
virtual void fbb3(){ cout << "Dervied2::fbb3" << endl;}
}; class Derived3:public Base1,public Base2,public Base3
{
public:
Derived3(int num_1,int num_2,int num_3):
Base1(num_1),Base2(num_2),Base3(num_3){}
virtual void fcc1(){ cout << "Dervied3::fcc1" << endl;}
virtual void fcc2(){ cout << "Dervied3::fcc2" << endl;}
}; class Dervied4:public Base1,public Base2,public Base3
{
public:
Dervied4(int num_1,int num_2,int num_3):
Base1(num_1),Base2(num_2),Base3(num_3){}
virtual void foo1(){ cout << "Dervied4::foo1" << endl;}
virtual void fdd(){ cout << "Dervied4::fdd" << endl;}
}; typedef void (*Fun)(void);
int main()
{
Base1* pBase1 = NULL;
Base2* pBase2 = NULL;
Base3* pBase3 = NULL;
Fun pFun; cout << "--------------------------------" << endl;
Derived1 d1(1);
pBase1 = &d1;
pBase1->foo1();
cout << "------------Derived1----------------" << endl;
pFun = (Fun)*((int*)*(int*)(&d1)+0);
pFun();
pFun = (Fun)*((int*)*(int*)(&d1)+1);
pFun();
pFun = (Fun)*((int*)*(int*)(&d1)+2);
pFun();
pFun = (Fun)*((int*)*(int*)(&d1)+3);
pFun();
pFun = (Fun)*((int*)*(int*)(&d1)+4);
pFun(); cout << "--------------------------------" << endl;
Derived2 d2(2);
pBase1 = &d2;
pBase1->foo2();
cout << "------------Derived2----------------" << endl;
pFun = (Fun)*((int*)*(int*)(&d2)+0);
pFun();
pFun = (Fun)*((int*)*(int*)(&d2)+1);
pFun();
pFun = (Fun)*((int*)*(int*)(&d2)+2);
pFun();
pFun = (Fun)*((int*)*(int*)(&d2)+3);
pFun();
pFun = (Fun)*((int*)*(int*)(&d2)+4);
pFun(); cout << "--------------------------------" << endl;
Derived3 d3(1,2,3);
pBase1 = &d3;
pBase2 = &d3;
pBase3 = &d3;
pBase1->foo1();
pBase2->foo1();
pBase3->foo1();
cout << "------------Derived3----------------" << endl;
pFun = (Fun)*((int*)*(int*)(&d3)+0);
pFun();
pFun = (Fun)*((int*)*(int*)(&d3)+1);
pFun();
pFun = (Fun)*((int*)*(int*)(&d3)+2);
pFun();
pFun = (Fun)*((int*)*(int*)(&d3)+3);
pFun();
pFun = (Fun)*((int*)*(int*)(&d3)+4);
pFun(); pFun = (Fun)*((int*)*((int*)(&d3)+2)+0); // Base1 有一个int 类型的成员变量
pFun();
pFun = (Fun)*((int*)*((int*)(&d3)+2)+1);
pFun();
pFun = (Fun)*((int*)*((int*)(&d3)+2)+2);
pFun(); pFun = (Fun)*((int*)*((int*)(&d3)+4)+0); // Base2 有一个int 类型的成员变量
pFun();
pFun = (Fun)*((int*)*((int*)(&d3)+4)+1);
pFun();
pFun = (Fun)*((int*)*((int*)(&d3)+4)+2);
pFun(); cout << "--------------------------------" << endl;
Dervied4 d4(1,2,3);
pBase1 = &d4;
pBase2 = &d4;
pBase3 = &d4;
pBase1->foo1();
pBase2->foo1();
pBase3->foo1();
cout << "------------Derived4----------------" << endl;
pFun = (Fun)*((int*)*(int*)(&d4)+0);
pFun();
pFun = (Fun)*((int*)*(int*)(&d4)+1);
pFun();
pFun = (Fun)*((int*)*(int*)(&d4)+2);
pFun();
pFun = (Fun)*((int*)*(int*)(&d4)+3);
pFun(); pFun = (Fun)*((int*)*((int*)(&d4)+2)+0); // Base1 有一个int 类型的成员变量
pFun();
pFun = (Fun)*((int*)*((int*)(&d4)+2)+1);
pFun();
pFun = (Fun)*((int*)*((int*)(&d4)+2)+2);
pFun(); pFun = (Fun)*((int*)*((int*)(&d4)+4)+0); // Base1 有一个int 类型的成员变量
pFun();
pFun = (Fun)*((int*)*((int*)(&d4)+4)+1);
pFun();
pFun = (Fun)*((int*)*((int*)(&d4)+4)+2);
pFun(); return 0;
}

运行结果:

--------------------------------
Base1:: foo11
------------Derived1----------------
Base1:: foo110843488
Base1:: foo210843488
Base1:: foo310843488
Dervied1::faa1
Dervied1::faa2
--------------------------------
Dervied2::foo2
------------Derived2----------------
Base1:: foo110843488
Dervied2::foo2
Base1:: foo310843488
Dervied2::fbb2
Dervied2::fbb3
--------------------------------
Base1:: foo11
Base2:: foo12
Base3:: foo13
------------Derived3----------------
Base1:: foo110843488
Base1:: foo210843488
Base1:: foo310843488
Dervied3::fcc1
Dervied3::fcc2
Base2:: foo110843488
Base2:: foo210843488
Base2:: foo310843488
Base3:: foo110843488
Base3:: foo210843488
Base3:: foo310843488
--------------------------------
Dervied4::foo1
Dervied4::foo1
Dervied4::foo1
------------Derived4----------------
Dervied4::foo1
Base1:: foo210843488
Base1:: foo310843488
Dervied4::fdd
Dervied4::foo1
Base2:: foo20
Base2:: foo30
Dervied4::foo1
Base3:: foo20
Base3:: foo30

C++ 虚函数表 多重继承的更多相关文章

  1. C++对象模型 多重继承与虚函数表

    一 多重继承 1) 代码: Code#include <iostream>using namespace std; class B1{public:    int x;    virtua ...

  2. 详谈C++虚函数表那回事(多重继承关系)

    上一篇说了一般继承,也就是单继承的虚函数表,接下来说说多重继承的虚函数表: 1.无虚函数覆盖的多重继承: 代码: #pragma once //无覆盖,多重继承 class Base1 { publi ...

  3. [C++对象模型][8]多重继承与虚函数表

    转载: [C++对象模型][8]多重继承与虚函数表 一 多重继承 1) 代码: Code #include <iostream> using namespace std; class B1 ...

  4. C++ 虚函数表与多态 —— 多重继承的虚函数表 & 内存布局

    多重继承的虚函数表会有两个虚表指针,分别指向两个虚函数表,如下代码中的 vptr_s_1.vptr_s_2,Son类继承自 Father 和 Mather 类,并且改写了 Father::func_1 ...

  5. C++ 虚函数表解析

    转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...

  6. C++虚函数表

    大家知道虚函数是通过一张虚函数表来实现的.在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承.覆盖的问题,其内容真是反应实际的函数.这样,在有虚函数的类的实例中,这个表分配在了这个实例的内存中 ...

  7. C++虚函数与虚函数表

    多态性可分为两类:静态多态和动态多态.函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的. 每个含有虚函数的类有一张虚函数表(vtbl),表中每一项是一个虚函数的地址, 也就是说 ...

  8. C++的虚函数表

    这里的例子全部来自陈皓的C++ 虚函数表解析,经过修改的. 编译器:g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2 环境:ubuntu 15.04  64位系统(地址占8字节) ...

  9. C++虚函数表原理

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技 ...

随机推荐

  1. Headless Chrome:服务端渲染JS站点的一个方案【中篇】【翻译】

    接上篇 防止重新渲染 其实说不对客户端代码做任何修改是忽悠人的.在我们的Express 应用中,通过Puppteer加载页面,提供给客户端响应,但是这个过程是有一些问题的. js脚本在服务端的Head ...

  2. swoole_proces实现多进程

    简介 swoole_process 是swoole提供的进程管理模块,用来替代PHP的pcntl扩展. 首先,确保安装的swoole版本大于1.7.2: $ php --ri swoole swool ...

  3. 线段树——codevs 1690 开关灯

    先来一发题目: 1690 开关灯 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description YYX家门前的街上有N(2<=N<=100000)盏路灯,在晚上六点 ...

  4. [HNOI 2009]最小圈

    Description 考虑带权的有向图$G=(V,E)$以及$w:E\rightarrow R$,每条边$e=(i,j)(i\neq j,i\in V,j\in V)$的权值定义为$w_{i,j}$ ...

  5. CSAPP-链接

    主要任务: 1.符号解析 在声明变量和函数之后,所有的符号声明都被保存到符号表. 而符号解析阶段会给每个符号一个定义. 2.重定位: 把每个符号的定义与一个内存位置关联起来,然后修改所有对这些符号的引 ...

  6. Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined)

    运气好,分到的房里我最先开始Hack C题,Hack了12个,听说F题沙雕莫队但我不会,最后剩不到15分钟想出E题做法打了一波结果挂了,最后虽然上分了但总有点不甘心. 最后A掉ABCD Hack+12 ...

  7. 「LibreOJ NOIP Round #1」旅游路线

    Description T 城是一个旅游城市,具有 nnn 个景点和 mmm 条道路,所有景点编号为 1,2,...,n1,2,...,n1,2,...,n.每条道路连接这 nnn 个景区中的某两个景 ...

  8. [APIO2013]

    A.机器人 题目大意:给定一个n*m的地图,有一些障碍物和k个机器人,你每次可以选择一个机器人往任意一个方向推,遇到转向器会转向,两个编号相邻的机器人可以合并,求最少推多少次可以全部合并. $n,m\ ...

  9. python+eclipse+pydev开发环境搭建

    1.安装配置python2.7(右击我的电脑->属性->高级系统设置->环境变量->系统变量列表中找到Path并双击->变量值中添加";C:\Python27; ...

  10. 用HTTP状态码实现提交表单后刷新页面不重复提交

    正常情况下,表单提交后如果用户刷新页面会重复提交表单,有些情况下我们不希望表单重复提交,利用HTTP协议中的307状态码重定向页面可以实现这个目的.实例如下: 表单页面代码: <form act ...