虚函数——虚表总结


非虚拟继承

【带虚函数的类】

class Base

{

public:

virtual void FunTest1()

{

cout<<"Base::FunTest1()"<<endl;

}

virtual void FunTest2()

{

cout<<"Base::FunTest2()"<<endl;

}

int _data1;

};

int main()

{

Base b;

b._data1 = 0x01;

return 0;

}

Base类没有显式定义自己的构造函数,此时编译器会和成默认的构造函数,

合成的构造函数中主要完成在对象头4个字节中填写虚表地址:

Base类对象最后的模型如下:

注意:同一个类的对象共用同一个虚表

从上述的结果中可以得到印证。

【单继承(派生类中没有虚函数覆盖)

class Base

{

public:

virtual void FunTest1()

{cout<<"Base::FunTest1()"<<endl;}

virtual void FunTest2()

{cout<<"Base::FunTest2()"<<endl;}

int _data1;

};

class Derive:public Base

{

public:

virtual void FunTest3()

{cout<<"Derive::FunTest3()"<<endl;}

virtual void FunTest4()

{cout<<"Derive::FunTest4()"<<endl;}

int _data2;

};

// 打印虚表

typedef void (*VtbFun)();

void PrintVtable()

{

cout<<"Derive类的虚函数表:"<<endl;

Derive d1;

d1._data1 = 0x01;

d1._data2 = 0x02;

int* pVTable = (int*)*(int*)&d1;

VtbFun FunTest = (VtbFun)*pVTable;

while(NULL != FunTest)

{

FunTest();

cout<<(int*)FunTest<<endl;

pVTable += 1;

FunTest = (VtbFun)*pVTable;

}

cout<<"虚表结束:"<<endl;

}

int main()

{

Base b1;

Derive d1;

return 0;

}

按照如上分析的顺序,探索下单继承下派生类对象模型以及虚表

首先看看编译器为派生类合成的缺省构造函数:

派生类构造函数中进行了如下事情:

Derive d1;

d1._data1 = 0x01;

d1._data2 = 0x02;

派生类最后的对象模型为:

【单继承(派生类中有虚函数覆盖)

class Base

{

public:

virtual void FunTest1()

{

cout<<"Base::FunTest1()"<<endl;

}

virtual void FunTest2()

{

cout<<"Base::FunTest2()"<<endl;

}

int _data1;

};

class Derive:public Base

{

public:

virtual void FunTest1()

{

cout<<"Derive::FunTest1()"<<endl;

}

virtual void FunTest3()

{

cout<<"Derive::FunTest3()"<<endl;

}

virtual void FunTest4()

{

cout<<"Derive::FunTest4()"<<endl;

}

int _data2;

};

int main()

{

PrintVtable();

return 0;

}

派生类对象模型及虚表建议规则:

【多继承(派生类不覆盖基类虚函数)

class Base

{

public:

virtual void FunTest1()

{

cout<<"Base::FunTest1()"<<endl;

}

virtual void FunTest2()

{

cout<<"Base::FunTest2()"<<endl;

}

int _data1;

};

class Base1

{

public:

virtual void FunTest3()

{

cout<<"Base1::FunTest3()"<<endl;

}

virtual void FunTest4()

{

cout<<"Base1::FunTest4()"<<endl;

}

int _data2;

};

class Derive:public Base, public Base1

{

public:

virtual void FunTest5()

{

cout<<"Derive::FunTest5()"<<endl;

}

int _data3;

};

int main()

{

cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl;

Derive d;

d._data1 = 0x01;

d._data2 = 0x02;

d._data3 = 0x03;

PrintVtable();

return 0;

}

同样:看看编译器合成的派生类的对象做了什么工作

观察下派生类的对象模型和虚表的建立过程

从上面的结果可以看出,Derive类自己特有的虚函数直接添加在Base类对应虚函数表最后的位置,大家可将BaseBase1的顺序交换验证下。

【多继承(派生类覆盖基类虚函数)

class Base

{

public:

virtual void FunTest1()

{

cout<<"Base::FunTest1()"<<endl;

}

virtual void FunTest2()

{

cout<<"Base::FunTest2()"<<endl;

}

int _data1;

};

class Base1

{

public:

virtual void FunTest3()

{

cout<<"Base1::FunTest3()"<<endl;

}

virtual void FunTest4()

{

cout<<"Base1::FunTest4()"<<endl;

}

int _data2;

};

// 这次将继承列表中Base和Base1的位置互换

class Derive:public Base1, public Base

{

public:

virtual void FunTest1()

{

cout<<"Derive::FunTest1()"<<endl;

}

virtual void FunTest3()

{

cout<<"Derive::FunTest3()"<<endl;

}

virtual void FunTest5()

{

cout<<"Derive::FunTest5()"<<endl;

}

int _data3;

};

int main()

{

PrintVtable();

return 0;

}

此时派生类的对象模型和虚表的结构:

虚拟继承

// 没有虚函数覆盖,但派生类有自己的虚函数

class Base

{

public:

virtual void FunTest1()

{

cout<<"Base::FunTest1()"<<endl;

}

virtual void FunTest2()

{

cout<<"Base::FunTest2()"<<endl;

}

int _data1;

};

class Derive:virtual public Base

{

public:

virtual void FunTest3()

{

cout<<"Derive::FunTest3()"<<endl;

}

virtual void FunTest4()

{

cout<<"Derive::FunTest4()"<<endl;

}

int _data2;

};

虚拟继承编译器为派生类合成的默认构造函数分析

编译器为派生类合成的默认构造函数任务分析:

虚拟继承派生类对象模型分析

时间: 2024-08-08 22:08:34

虚函数——虚表总结的相关文章

c++虚函数&amp;重写

虚函数是C++中实现多态的一种方法,父类A的一个函数声明为虚函数,在子类B中覆盖定义之后,当在调用的时候使用A*a=new B(),此时调用对应的那个虚函数的名字,则会执行B中的函数.当父类中没有定义虚函数的实体时候,virtual void foo()=0:这个函数就是一个纯虚函数,对应的父类就是抽象类,则这个抽象类不能被实例化,只能由子类派生实例化. 每个含有虚函数的对象都有一个虚指针,这个虚指针和这个对象的基地址是一样的,即一个对象的第一块内存单元存储的一定这个类对象的虚指针. 普通继承中

类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)

原理分析 当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[0](param1, param2)这样的函数. 已经不是在调用函数名了. 当我们将虚表地址[n]中的函数实现改为另外的函数, 虚函数的实现就由我们来控制了. 实验 根据虚表原理, 实验一下修改自己程序的虚函数表项地址. 使编译器生成的代码执行一个虚函数A时, 执行的是我们自己定义的非虚函数B. 知识点 * 使用union赋值, 绕过编译器函数与变量强转赋值的限制 * 类成员函数指针的执行 * 修改和恢复自己的代码段属性 * 虚函

在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现

前言 当类没有成员变量的情况下,   类首地址有4个字节的空间, 这里可以放我们模拟出来的虚表入口地址. 当类有成员变量的情况下, 类首地址就是成员变量,  所以, 为了模拟虚表实现, 需要在成员变量前, 再定义一个int型变量, 用来存放模拟的虚表入口地址. 现在还得不到虚析构函数的地址, 暂时按照非虚析构函数进行模拟. 这个实验是在C++中模拟的. 模拟虚函数实现的用途 在非OOP语言(C语言)中, 模拟类的实现, 可以实现虚函数的效果. 效果 工程下载点 编译环境: vc6sp6 + wi

C++学习 - 虚表,虚函数,虚函数表指针学习笔记

虚函数 虚函数就是用virtual来修饰的函数.虚函数是实现C++多态的基础. 虚表 每个类都会为自己类的虚函数创建一个表,来存放类内部的虚函数成员. 虚函数表指针 每个类在构造函数里面进行虚表和虚表指针的初始化. 下面看一段代码: // // main.cpp // VirtualTable // // Created by Alps on 15/4/14. // Copyright (c) 2015年 chen. All rights reserved. // #include <iostr

C++虚函数:虚指针、虚表、虚函数入口地址

测试程序: //test.c #include"stdio.h" #include"string.h" class GSVirtual { public: void gsv(char *src) { char buf[200]; strcpy(buf,src); vir2(); } virtual void vir1() { printf("vir1"); } virtual void vir2() { printf("vir2&quo

如何理解虚表及其计算含虚函数的类的大小

在什么情况下系统会自动生成缺省(默认)的构造函数? 1.在类里面有一个类类型的对象,这个类有自己的缺省构造函数(有缺省的参数,参数有缺省值). class B { B(int data) {  } };不能合成 class B { B(int data=0) {  } };会合成 class B { public: B(int data=0) {  } }; class C:public B { public: C() :B(0) {  } B b;  //编译器会自动合成 }; 2.类是虚拟继

获取C++虚表地址和虚函数地址

获取C++虚表地址和虚函数地址 By qianghaohao 学过C++的应该都对虚表有所耳闻,在此就不过多介绍概念了,通过实 例来演示一下如何获取虚表地址和虚函数地址. 简单说一下虚表的概念:在一个类中如果有虚函数,那么此类的实例中就有 一个虚表指针指向虚表,这个虚表是一块儿专门存放类的虚函数地址的内存. 图示说明本文的主题(先看图更容易后面代码中的指针操作): 代码如下(要讲解的都在代码的注释中说明了): class Base { public: virtual void f() { cou

C++反汇编第二讲,反汇编中识别虚表指针,以及指向的虚函数地址

讲解之前,了解下什么是虚函数,什么是虚表指针,了解下语法,(也算复习了) 开发知识为了不码字了,找了一篇介绍比较好的,这里我扣过来了,当然也可以看原博客链接: http://blog.csdn.net/hackbuteer1/article/details/7558868 一丶虚函数讲解(复习开发,熟悉内存模型) 1.复习开发知识 首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数

多态&amp;虚函数

(1).对象类型: a.静态类型:对象声明时的类型,编译的时候确定 b.动态类型:对象的类型是运行时才能确定的 class A {}; class B:public A {}; int main() { B* b; A* a=b;//a的静态类型是A*,动态类型(运行时)类型是B* return 0; } (2).多态 a.静态多态:函数重载.泛性编程 int Add(int a,int b) { return a+b; } float Add(float a,float b) { return