C++中虚函数工作原理和(虚)继承类的内存占用大小计算

一、虚继承情况下类的内存大小计算

当每个基类中有多个虚函数时,并且在虚继承的情况下,内存是如何分配的,如何计算类的大小,下面举例说明:

#include<iostream>

using namespace std;

class A

{

public:

int a;

virtual void aa(){};

};

class D

{

public:

virtual void dd(){};

};

class C

{

public:

virtual void cc(){};

};

class B : virtual public  A,virtual public  D, virtual public  C

{

public:

int a;

virtual void bb(){};

};

sizeof(B) = 28,B类中虽然虚继承了多个基类(A、D、C),但是只有一个指向基类的虚基类指针,而却有多个虚函数表的指针,当B类未对三个基类A、D、C的虚函数进行重写的时候,它们四个类分别有指向自己虚函数表的虚函数指针。当B类对基类A的虚函数进行覆盖写的时候,内存发生了变化,此时sizeof(B) = 24 。B类的虚函数表就对A进行了修改。内存分配的新图如下:

class A

{

public:

int a;

virtual void aa(){};

};

class D

{

public:

virtual void dd(){};

};

class C

{

public:

virtual void cc(){};

};

class B : virtual public  A,virtual public  D, virtual public  C

{

public:

int a;

virtual void aa(){};

};

二、普通继承情况下类的内存大小计算

当每个基类中有多个虚函数时,并且在普通继承的情况下,内存是如何分配的,如何计算类的大小,下面举例说明:

#include<iostream>

using namespace std;

class A

{

public:

int a;

virtual void aa(){};

};

class D

{

public:

virtual void dd(){};

};

class C

{

public:

virtual void cc(){};

};

class B : public  A,public  D, public  C

{

public:

int a;

virtual void bb(){};

};

sizeof(B) = 20,B类中虽然虚继承了多个基类(A、D、C),但是只有一个指向基类的虚基类指针,而却有多个虚函数表的指针,当B类未对三个基类A、D、C的虚函数进行重写的时候,B类的虚函数的指针默认放在第一个继承的基类A的后面。当B类对基类A的虚函数进行覆盖写的时候,B类的虚函数指针对A类覆盖写的函数指针进行了覆盖,此时sizeof(B) = 20 。B类的虚函数表就对A进行了修改。内存分配的新图如下:

#include<iostream>

using namespace std;

class A

{

public:

int a;

virtual void aa(){};

};

class D

{

public:

virtual void dd(){};

};

class C

{

public:

virtual void cc(){};

};

class B : public  A,public  D, public  C

{

public:

int a;

virtual void aa(){};

};

综上所述:虚继承和普通继承的差别在于是否有一个指向基类地址的虚基类指针vbptr。

在虚继承的情况下,如果派生类没有对基类的虚函数进行覆盖写,它由自己对应的虚函数表指针指向它的虚函数表,但是,当其对某个基类的虚函数进行覆盖写的时候,它的虚函数地址就覆盖写了对应基类的虚函数表中,不再有自己独立的虚函数表指针。

在普通继承的情况下,如果派生类没有对基类虚函数进行了覆盖写,它的虚函数地址后默认跟在第一个继承的基类后面,如果当对某个基类的函数进行覆盖写的时候,它的虚函数地址就覆盖写了对应基类的虚函数表中。在普通继承的情况下,派生类不具有自己独立的虚函数表指针。

下面是一个比较复杂的例子,在利用虚继承之后,又把虚继承几个类进行普通继承,注意此时普通继承是,就有了每个分别执行各自基类的虚基类指针。

class CommonBase

{

int co;

};

class Base1: virtual public CommonBase

{

public:

virtual void print1() {  }

virtual void print2() {  }

private:

int b1;

};

class Base2: virtual public CommonBase

{

public:

virtual void dump1() {  }

virtual void dump2() {  }

private:

int b2;

};

class Base3: virtual public CommonBase

{

public:

virtual void dump1() {  }

virtual void dump2() {  }

private:

int b3;

};

class Derived: public Base1, public Base2  ,public Base3

{

public:

void print2() {  }

void dump2() {  }

private:

int d;

};

sizeof(Derived) = 44

VS2010命令行下查看虚函数表和类内存布局

在学习多重继承下的Virtual functions时,需要分析派生类的虚函数表(vtable),但是在网上找了好几种Hack vtable方法,结果都不尽如人意。没想到MS Compiler(以VS2010为例)有打印vtable的编译选项,真是太好了!

1. 打开“Visual Studio Command Prompt (2010)”,如下

该CMD下具有VS2010命令行下的一些编译、链接等工具,例如cl.exe。

2、使用cl命令的/d1 reportAllClassLayout或reportSingleClassLayoutXXX选项。这里的reportAllClassLayout选项会打印大量相关类的信息,一般用处不大。而reportSingleClassLayoutXXX选项的XXX代表要编译的代码中类的名字(这里XXX类),打印XXX类的内存布局和虚函数表(如果代码中没有对应的类,则选项无效)。

举例如下

cl /d1 reportSingleClassLayoutBase1 160.cpp

时间: 2024-10-12 19:06:42

C++中虚函数工作原理和(虚)继承类的内存占用大小计算的相关文章

虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout << "A:A" <<endl; } virtual void getb(){ cout << "A:B" <<endl; } }; class B :public A{ public: B(){} virtual void g

C++中虚函数工作原理和(虚)继承类…

转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7883531 一.虚函数的工作原理 虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数.典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式.vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl.当

C++中虚函数工作原理

一.虚函数的工作原理 虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数.典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式.vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl.当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的 vptr 指向的 vtbl,然后在 vtbl 中寻找合适的函数指针. 

虚函数实现原理之虚函数表

引言 C++使用虚函数来实现多态机制,大多数编译器是通过虚函数表来实现动态绑定. 类的内存布局 1.普通类 class B { public: int m; int n; }; int main() { printf("%ld\n", sizeof(B)); B b; printf("%p, %p, %p\n", &b, &b.m, &b.n); return 0; } 类中只有普通成员变量,对象在内存中顺序存储成员变量.输出: 8 0x7f

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

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

C++中虚函数实现原理揭秘

编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟.      编译器对每个包含虚函数的类创建一个表(称为V TA B L E).在V TA B L E中,编译器放置特定类的虚函数地址.在每个带有虚函数的类 中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E.通过基类指针做虚函数调 用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使

C++之虚函数的原理

1. 看看一个类中如果有虚函数,它的内存布局: class A{ double i; int j; virtual void foo(){} virtual void fun(){} }; 内存布局: 1> class A size(24): 1> +--- 1> 0 | {vfptr} 1> 8 | i 1> 16 | j 1> | <alignment member> (size=4) 1> +--- 可以看出,A中有一个vfptr,这个是指向一个

C++中为什么构造函数不能是虚函数,析构函数是虚函数

一, 什么是虚函数? 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离:用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略. 所谓虚函数就是多态情况下只执行一个,而从继承的概念来讲,总是要先构造父类对象,然后才能是子类对象,如果构造函数设为虚函数,那么当你在构造父类的构造函数时就不得不显示的调用构造,还有一个原因就是为了防错,试想如果你在子类中一不小心重写了个跟

C++虚函数实现原理详解

前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的书籍.在这篇文章中,我只想从虚函数的实现机制上面为大家