C++中虚拟继承 & 虚函数表内存分布情况

一 虚继承

1) 代码:

Code

#include <iostream>

using namespace std;

class B

{

public:

int i;

virtual void vB(){ cout << "B::vB" << endl; }

void fB(){ cout << "B::fB" << endl;}

};

class D1 : virtual public B

{

public:

int x;

virtual void vD1(){ cout << "D1::vD1" << endl; }

void fD1(){ cout << "D1::fD1" << endl;}

};

class D2 : virtual public B

{

public:

int y;

void vB(){ cout << "D2::vB" << endl;}

virtual void vD2(){ cout << "D2::vD2" << endl;}

void fD2(){ cout << "D2::fD2" << endl;}

};

class GD :  public D1, public D2

{

public:

int a;

void vB(){ cout << "GD::vB" << endl;}

void vD1(){cout << "GD::vD1" << endl;}

virtual void vGD(){cout << "GD::vGD" << endl;}

void fGD(){cout << "GD::fGD" << endl;}

};

2)类图:

3)VS2008的编译选项查看布局:

4)可视化表示:

5)代码验证:(此时的虚函数表不是以NULL结尾,为什么?)

Code

typedef void (*Fun)();

void PrintMember(int *pI)

{

cout << *pI << endl << endl;

}

void PrintVT(int *pVT)

{

while(*pVT != NULL)

{

(*(Fun*)(pVT))();

pVT++;

}

}

void PrintMemberAndVT(GD *pGD)

{

int *pRoot = (int*)pGD;

int *pD1VT = (int*)*(pRoot + 0);

(*(Fun*)(pD1VT))(); (*(Fun*)(pD1VT +1))();

int *pVB = (int*)*(pRoot +1);  cout << "vbtable‘s adress:" << *pVB << endl;

int *pX = (pRoot + 2); PrintMember(pX);

int *pD2VT = (int*)*(pRoot + 3);

(*(Fun*)(pD2VT))();

int *pVB2 = (int*)*(pRoot +4); cout << "vbtable‘s adress:" << *pVB2 << endl;

int *pY = (pRoot + 5); PrintMember(pY);

int *pA = (pRoot + 6); PrintMember(pA);

int *pBVT = (int*)*(pRoot + 7);

(*(Fun*)(pBVT))();

int *pI = (pRoot + 8); PrintMember(pI);

}

void TestVT()

{

B *pB = new GD();

GD *pGD = dynamic_cast<GD*>(pB);

pGD->i = 10;

pGD->x = 20;

pGD->y = 30;

pGD->a = 40;

PrintMemberAndVT(pGD);

delete pGD;

}

6)验证代码结果:

7)总结:

虚继承,使公共的基类在子类中只有一份,我们看到虚继承在多重继承的基础上多了vbtable来存储到公共基类的偏移。

二 虚继承运行时类型转化

1)代码验证:

Code

void TestDynamicCast()

{

B *pB = new GD();

GD *pGD = dynamic_cast<GD*>(pB);

cout << "GD:" << pGD << endl;

D1 *pD1 = dynamic_cast<D1*>(pB);

cout << "D1:" << pD1 << endl;

D2 *pD2 = dynamic_cast<D2*>(pB);

cout << "D2:" << pD2 << endl;

cout << "B:" << pB << endl;

}

2)验证代码结果:

3)总结:

还是从内存布局来看dynamic_cast时地址的变化,第一个基类的地址与子类相同,其他的基类和虚基类需要做偏移。

三 完!

时间: 2024-10-31 11:27:41

C++中虚拟继承 & 虚函数表内存分布情况的相关文章

菱形虚拟继承&虚函数表&对象模型

菱形继承: Assitant的菱形继承对象模型 Assitant中有两份Person成员,存在二义性和数据冗余. 所以我们引出了虚拟继承. virtual虚继.不会在子类中创建父类成员,但是子类中可以引用,就像指针一样.主要用在菱形继承,也叫钻石继承. 虚拟继承对象模型 class Student : vitrual public Person class Teacher : virtual public Peraon 虚函数表 通过一块连续内存来存储虚函数的地址.这张表解决了继承.虚函数(重写

C++ 虚函数表解析 继承

C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述

C++多态篇3——虚函数表详解之多继承、虚函数表的打印

在上上一篇C++多态篇1一静态联编,动态联编.虚函数与虚函数表vtable中,我最后简单了剖析了一下虚函数表以及vptr. 而在上一篇文章C++多态篇2--虚函数表详解之从内存布局看函数重载,函数覆盖,函数隐藏中我详细介绍了虚函数的函数重载,函数覆盖以及函数隐藏的问题,其实在那一篇文章中,对单继承的虚函数已经做了十分详细的解答了,如果对前面有兴趣的人可以先看一下那篇文章. 在这一篇中,我会具体的分析一下在不同继承中(单继承,多继承)关于虚函数表在内存中的布局以及如何打印虚函数表.但是有关在虚继承

C++中的虚函数表

学习了虚基类,立马就会想到虚函数,虚基类有个虚基类表与之对应,才使其发挥了不一般的作用,当然虚函数也有一个不函数表,其原理如下所示: 1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的. 2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数. 3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象. 4.内联(inline)函数不

C++ 虚函数表解析

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

C++ 虚函数表解析(转)

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

c++ 虚函数表

转自 http://blog.csdn.net/haoel/article/details/1948051/ C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,

C++入门学习——虚函数表介绍

多态 多态是指使用相同的函数名来访问函数不同的实现方法,可以简单概括为"一种接口,多种方法". C++支持编译时多态(也叫静态多态)和运行时多态(也叫动态多态),运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态. 静态多态与动态多态的实质区别就是函数地址是早绑定还是晚绑定.如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态多态(编译时多态),就是说地址是早绑定的.而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定,是

C++虚函数表原理

C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,说白了就是试图 使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 对C++了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-T