【VC++】虚函数 内存结构 - 第五篇(多重继承,有虚函数覆盖)
#include <IOSTREAM>
using namespace std;
class Base1
{
public:
int nBase1;
int nBase2;
Base1(int n1,int n2):nBase1(n1),nBase2(n2)
{
cout<<"Base1::Base1("<<n1<<","<<n2<<")"<<endl;
}
virtual void F()
{
cout<<"Base1::F()"<<endl;
}
virtual void G()
{
cout<<"Base1::G()"<<endl;
}
};
class Base2
{
public:
int nBase1;
int nBase2;
Base2(int n1,int n2):nBase1(n1),nBase2(n2)
{
cout<<"Base2::Base2("<<n1<<","<<n2<<")"<<endl;
}
virtual void F()
{
cout<<"Base2::F()"<<endl;
}
virtual void G()
{
cout<<"Base2::G()"<<endl;
}
};
class Derive:public Base1, public Base2
{
public:
int nBase1; //与父类成员变量名一样
int nDerive2;
Derive(int n1,int n2,int n3,int n4,int n5,int n6):Base1(n1,n2),Base2(n3,n4),nBase1(n5),nDerive2(n6)
{
cout<<"Derive::Derive("<<n5<<","<<n6<<")"<<endl;
}
virtual void F()
{
cout<<"Derive::F()"<<endl;
}
virtual void G2()
{
cout<<"Derive::G2()"<<endl;
}
};
typedef void(*Fun)(void);
void TestBase1(Base1 &b)
{
Fun pFun = NULL;
int** pVtab = (int**)&b;
cout << "类对象地址 / 虚函数表指针的地址:" << (&b) << " / " << pVtab << endl;
cout << "虚函数表指针值(虚函数表的地址)(十进制):" << (int)pVtab[0] <<endl;
cout << "虚函数表指针值(虚函数表的地址)(十六进制):" << pVtab[0] <<endl;
cout << "虚函数表 — 第 1 个函数地址的地址:" << &pVtab[0][0] << " , "; //好比一个变量的地址
cout << "函数地址值:" << (int*)pVtab[0][0] << " 调:"; //好比一个变量的值(这个值也是个地址)
pFun = (Fun)pVtab[0][0];
pFun();
cout << "虚函数表 — 第 2 个函数地址的地址:" << &pVtab[0][1] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][1] << " 调:";
pFun = (Fun)pVtab[0][1];
pFun();
cout << "虚函数表 — 第 3 个函数地址的地址:" << &pVtab[0][2] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][2] <<endl ; //如果仅有一个虚函数,后面的节点不是NULL???
//pFun = (Fun)pVtab[0][2];
//pFun();
cout << "类对象 — 第 1 个变量地址:" << &pVtab[1] << " 值:"<< (int)pVtab[1] <<endl;
cout << "类对象 — 第 2 个变量地址:" << &pVtab[2] << " 值:"<< (int)pVtab[2] <<endl;
cout << "类对象 — 第 3 个变量地址:" << &pVtab[3] << " 值:"<< (int)pVtab[3] <<endl; //之后的内存是什么???
cout<<endl;
}
void TestBase2(Base2 &b)
{
Fun pFun = NULL;
int** pVtab = (int**)&b;
cout << "类对象地址 / 虚函数表指针的地址:" << (&b) << " / " << pVtab << endl;
cout << "虚函数表指针值(虚函数表的地址)(十进制):" << (int)pVtab[0] <<endl;
cout << "虚函数表指针值(虚函数表的地址)(十六进制):" << pVtab[0] <<endl;
cout << "虚函数表 — 第 1 个函数地址的地址:" << &pVtab[0][0] << " , "; //好比一个变量的地址
cout << "函数地址值:" << (int*)pVtab[0][0] << " 调:"; //好比一个变量的值(这个值也是个地址)
pFun = (Fun)pVtab[0][0];
pFun();
cout << "虚函数表 — 第 2 个函数地址的地址:" << &pVtab[0][1] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][1] << " 调:";
pFun = (Fun)pVtab[0][1];
pFun();
cout << "虚函数表 — 第 3 个函数地址的地址:" << &pVtab[0][2] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][2] <<endl ; //如果仅有一个虚函数,后面的节点不是NULL???
//pFun = (Fun)pVtab[0][2];
//pFun();
cout << "类对象 — 第 1 个变量地址:" << &pVtab[1] << " 值:"<< (int)pVtab[1] <<endl;
cout << "类对象 — 第 2 个变量地址:" << &pVtab[2] << " 值:"<< (int)pVtab[2] <<endl;
cout << "类对象 — 第 3 个变量地址:" << &pVtab[3] << " 值:"<< (int)pVtab[3] <<endl; //之后的内存是什么???
cout<<endl;
}
void TestDerive(Derive &d)
{
Fun pFun = NULL;
int** pVtab = (int**)&d;
cout << "类对象地址 / 虚函数表指针的地址:" << (&d) << " / " << pVtab << endl;
cout << "虚函数表指针值(虚函数表的地址)(十进制):" << (int)pVtab[0] <<endl;
cout << "虚函数表指针值(虚函数表的地址)(十六进制):" << pVtab[0] <<endl;
cout << "虚函数表 — 第 1 个函数地址的地址:" << &pVtab[0][0] << " , "; //好比一个变量的地址
cout << "函数地址值:" << (int*)pVtab[0][0] << " 调:"; //好比一个变量的值(这个值也是个地址)
pFun = (Fun)pVtab[0][0];
pFun();
cout << "虚函数表 — 第 2 个函数地址的地址:" << &pVtab[0][1] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][1] << " 调:";
pFun = (Fun)pVtab[0][1];
pFun();
cout << "虚函数表 — 第 3 个函数地址的地址:" << &pVtab[0][2] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][2] << " 调:";
pFun = (Fun)pVtab[0][2];
pFun();
cout << "虚函数表 — 第 4 个函数地址的地址:" << &pVtab[0][3] << " , ";
cout << "函数地址值:" << (int*)pVtab[0][3] << endl;
cout << "类对象 — 第 1 个变量地址:" << &pVtab[1] << " 值:"<< (int)pVtab[1] <<endl;
cout << "类对象 — 第 2 个变量地址:" << &pVtab[2] << " 值:"<< (int)pVtab[2] <<endl;
//cout << "类对象 — 第 3 个变量地址:" << &pVtab[3] << " 值:"<< (int)pVtab[3] <<endl;
//第 2 个虚函数表
cout << "第 2 个虚函数表指针的地址:" << &pVtab[3] << endl;
cout << "第 2 个虚函数表指针值(虚函数表的地址)(十进制):" << (int)pVtab[3] <<endl;
cout << "第 2 个虚函数表指针值(虚函数表的地址)(十六进制):" << pVtab[3] <<endl;
cout << "第 2 个虚函数表 — 第 1 个函数地址的地址:" << &pVtab[3][0] << " , "; //好比一个变量的地址
cout << "函数地址值:" << (int*)pVtab[3][0] << " 调:"; //好比一个变量的值(这个值也是个地址)
pFun = (Fun)pVtab[3][0];
pFun();
cout << "第 2 个虚函数表 — 第 2 个函数地址的地址:" << &pVtab[3][1] << " , ";
cout << "函数地址值:" << (int*)pVtab[3][1] << " 调:";
pFun = (Fun)pVtab[3][1];
pFun();
cout << "第 2 个虚函数表 — 第 3 个函数地址的地址:" << &pVtab[3][2] << " , ";
cout << "函数地址值:" << (int*)pVtab[3][2] << endl;
//
cout << "类对象 — 第 3 个变量地址:" << &pVtab[4] << " 值:"<< (int)pVtab[4] <<endl;
cout << "类对象 — 第 4 个变量地址:" << &pVtab[5] << " 值:"<< (int)pVtab[5] <<endl;
cout << "类对象 — 第 5 个变量地址:" << &pVtab[6] << " 值:"<< (int)pVtab[6] <<endl;
cout << "类对象 — 第 6 个变量地址:" << &pVtab[7] << " 值:"<< (int)pVtab[7] <<endl;
cout << "类对象 — 第 7 个变量地址:" << &pVtab[8] << " 值:"<< (int)pVtab[8] <<endl;
cout<<endl;
}
void main()
{
Base1 b1(123,321);
Base2 b2(456,654);
Derive d(111,222,333,444,555,666);
TestBase1(b1);
TestBase2(b2);
TestDerive(d);
cout<<"d.nBase1: "<<d.nBase1<<endl;
cout<<"d.Base1::nBase1: "<<d.Base1::nBase1<<endl;
cout<<"d.Base2::nBase1: "<<d.Base2::nBase1<<endl;
cout<<endl;
}
运行结果:
先 与上一篇文章的代码 比对(红色表示不同的地方):
再 与上一篇文章的运行结果 比对(除了地址不同,蓝框重点标出虚函数的不同):
类图、监视值(可以看到,VS的监视值并不全面,还是以实际打印的为准):
在内存中的结构是:
在本文结束前,我也还是来介绍下自己吧。我从03年初学编程,一直到现在都在做软件开发方面的事,做过VC++、VB/Delphi/C++Builder、C#/Asp.Net、Java、Web前后端、数据库、服务器端、客户端、js、lua、Flash AS、cocos2dx/Unity3d……都有接触过,甚至做过很长一段时间的运营、产品策划、美工、客服、线下推广员、公司经理 多职务……技术只是一种工具,用来实现业务需求,所以最大的特长是逻辑思维、挖掘业务需求、强化用户体验、快速的产品实现,最自以为豪的,我做过的很多产品,很稳定,bug极少(当然也出现过没考虑周全的漏洞在所难免但总体上也还算少),有很多独立开发的游戏运营到现在还在稳定的运行。不是技术极客,而是业务需求带动技术的学习研究,所以也不怎么挑语言,编程语言大体上也都是相通的,底层原理也有很多类同的地方。所以缺点从不敢说精通哪一门语言。遇到小工具、小需求的订制实现,我个人最喜欢的还是用VC6,简洁干净,编译出来的东西 体积小,速度快,占CPU内存小。当然实际工作中,还是随项目。欢迎大家和我交流,我的QQ是:七6.肆-陆_柒-4`7_四.
生活中的我,热爱 街舞、飙车、花式游泳、游戏一条命通关……极限运动,我抖音号(一不小心玩出花样)是:1917940952
加上父类的对象,更详细的内存结构图是:
文章没有考虑字节对齐(都用默认的字节对齐),并且是在32位环境下,VC6、VS2017 都测试过。
cout<<"sizeof(Base1): "<<sizeof(Base1)<<endl;
cout<<"sizeof(Base2): "<<sizeof(Base2)<<endl;
cout<<"sizeof(Derive): "<<sizeof(Derive)<<endl;
/*
打印结果:
sizeof(Base1): 12
sizeof(Base2): 12
sizeof(Derive): 32
*/
(转载时请注明作者和出处。未经许可,请勿用于商业用途)
原创出处:https://blog.csdn.net/maoyeahcom/article/details/108873594