IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 深度探索c++对象模型-23-多继承第二基类虚函数支持、虚继承带虚函数 -> 正文阅读

[C++知识库]深度探索c++对象模型-23-多继承第二基类虚函数支持、虚继承带虚函数

一、多重继承第二基类对虚函数支持的影响(this指针调整作用)

子类继承了几个父类,子类就有几个虚函数表
this指针调整的目的就是让对象指针正确的指向对象的首地址,从而能正确的调用对象的成员函数或者说正确确定数据成员的存储位置。

看如下代码:

class Base
{
public:

	Base()
	{
		printf("Base::this = %p\n",this);
	}
	virtual void f()
	{
		cout << "Base:f()" << endl;
	}

	virtual void g()
	{
		cout << "Base:g()" << endl;
	}


	virtual void h()
	{
		cout << "Base:h()" << endl;
	}

	virtual ~Base()
	{
		cout << "Base::~Base()" << endl;
	}
};

class Base2
{
public:
	virtual void hBase2()
	{
		cout << "Base2:hBase2" << endl;
	}

	virtual ~Base2()
	{
		cout << "Base2::~Base2()" << endl;
	}
};


class Derive :public Base, public Base2
{
public:

	Derive()
	{
		printf("Derive::this = %p\n", this);
	}

	virtual void g()
	{
		cout << "Derive:g()" << endl;
	}

	virtual void i()
	{
		cout << "Derive:g()" << endl;
	}
	~Derive()
	{
		cout << "Derive::~Derive()" << endl;
	}
};

1.通过指向第二个 基类的指针调用继承类的虚函数时

Base2 *pb2 = new Derive;	
delete pb2;

上一节已经说过了,pb2指向Derive对象中的第二基类(Base2),所以为了能够正确执行derive的析构函数,pb2必须要调整指向Derive对象首地址(减掉4)。

2.一个指向派生类的指针调用第二基类中的虚函数时

Derive *pd= new Derive;
pd->hBase2();
delete pd;

上述代码hBase2()是第二基类中函数,要想成功调用,必须对this指针进行调整,让this指针指向Base2的类子对象的首地址。
看下面反汇编代码:
在这里插入图片描述
其中有一句 add ecx,4就是说this指向向下移动4个字节(+4)。这也及时Base2的首地址。

在这里插入图片描述
3.允许虚函数的返回值类型有所变化时
分别在Base,Base2,Dervie中增加如下的代码:

virtual Base *clone() const
	{
		return new Base();
	}
virtual Base2 *clone() const
	{
		return new Base2();
	}
virtual Derive *clone() const
	{
		return new Derive();
	}
void main()
{

	Base2 *pb1 = new Derive;
	Base2 *pb2 = pb1->clone();

	system("pause");
}

其中

pb1->clone();//将执行Derive::clone()

因为它是虚函数,动态绑定。执行时,pb1首先会将this指针调整到Derive对象的开始地址,这样调用的才是Derive的clone(),所以this指针应该减小。

在这里插入图片描述
可以看到有两个thunk,转到反汇编:
在这里插入图片描述
注意那个+8,其实也就是调用虚函数表中[2](也就是第二个thunk),继续执行到call
在这里插入图片描述
在这里插入图片描述
注意sub ecx,4这就意味着this指针往回走了4个字节,正好走到了真实的Derive对象的首地址,然后jmp跳转到Derive::clone().

执行完Derive::clone()后返回的是Derive对象的指针,但是是用Base2 *去接的,这样就还需要进行一个this指针调整,也就是往后走4个字节(+4),让其指向Base2对象的首地址。
二、虚继承下的虚函数
看如下代码:

class Base
{
public:

	int m_nbase1;
	virtual void f()
	{
		cout << "Base:f()" << endl;
	}

	
	virtual ~Base()
	{
		cout << "Base::~Base()" << endl;
	}


};

class Derive :public virtual Base
{
public:

	int m_nderive;

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


};


void main()
{

	cout << "sizeof(Derive) = " << sizeof(Derive) << endl;
	Derive dobj;
	dobj.m_nbase1 = 2;
	dobj.m_nderive = 5;

	Derive *pdobj = new Derive;
	pdobj->f();

	system("pause");
}

加个断点,位置如下:
在这里插入图片描述
切换到内存,如下:
因为是16个字节,所以我们只看16个字节,如下:
在这里插入图片描述
从这个布局我们可以推算出如下的布局:
在这里插入图片描述
其实上面连个问号,一个是虚函数表指针,一个是虚基类表指针,只是不知道哪个在哪个位置,接下来就是如何确定他们的位置。

接下来这么调用:

Derive *pdobj = new Derive;
pdobj->m_nbase1 = 2;
pdobj->m_nderive = 5;
pdobj->f();

由前面的内容,已经知道了第,第2,第4格的内容分别是5,2。那虚函数表的地址,不是第1格,就在第3格子,假设在第3格,

下面是pdobj的内存地址:
在这里插入图片描述
下面是pdobj的内存,我们查看它第三格的地址,也就是如下的地址:0x002becbc (和显示的反着),接下来去这个地址看看:
在这里插入图片描述
反过来就是002b1398

看看调用f()的汇编代码:
在这里插入图片描述

下面是寄存器的地址
在这里插入图片描述
其实eax中的值也就是f()的地址。如下证明:
在这里插入图片描述

这和第三格里面的内容一致,所以虚函数表指针在第三格,所以布局如下:
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 20:46:10  更:2021-08-02 20:46:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 15:20:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码