多态 多继承的虚表深度剖析 (3)

💯 博客内容:多态

😀 作  者:陈大大陈

🚀 个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!

💖 欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信 😘 😘 😘

目录

普通菱形继承

虚表指针偏移

菱形虚继承的情况


普通菱形继承

cpp 复制代码
class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};

class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};

class Derive : public Base1, public Base2 {
public:
	virtual void func1() 
	{ 
		cout << "Derive::func1" << endl;
	}

	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};

int main()
{
	Derive d;
	return 0;
}

上面这种多继承的情况,Derive有几个虚表呢?

答案是,因为继承了Base1和Base2两个类,所以有两个虚表。

但是这样的话,就会衍生出一个问题,它自己的虚函数也就是func3放在哪里呢?

我没看到,编译器仍旧是故技重施,欺骗我们的眼睛,我们检测监测不到func3。

我们打印一下第一张虚表,这很容易想到。

cpp 复制代码
class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};

class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};

class Derive : public Base1, public Base2 {
public:
	virtual void func1() 
	{ 
		cout << "Derive::func1" << endl;
	}

	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};

int main()
{
	Derive d;
	//打印第一张虚表
	PrintVFT((VFUNC*)(*(int*)&d));
	return 0;
}

虚表指针偏移

那么,怎么打印第二张虚表呢?

cpp 复制代码
PrintVFT((VFUNC*)(*(int*)((char*)&d+sizeof(Base1))));

这么打印,需要注意的是,d是一个Derive类,加一的话会加上一个Derive的大小。

所以这里必须把它强制类型转换成char*。

其实也可以这么打印。

cpp 复制代码
PrintVFT((VFUNC*)(*(int*)((Base1*)&d+1)));

结果是一样的。

还可以这样写,最聪明的一种写法。

cpp 复制代码
	Base2* ptr = &d;
	PrintVFT((VFUNC*)(*(int*)ptr));

Base2指针会自己切割,便宜到Base2那里。

我们得到结论,func3放到了第一个虚表里面。

菱形虚继承的情况

cpp 复制代码
class A
{
public:
	virtual void func1() 
	{ 
		cout << "A::func1" << endl;
	}
public:
	int _a;
};


class B : public A
{
public:
	virtual void func1()
	{
		cout << "B::func1" << endl;
	}

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

public:
	int _b;
};


class C : public A
{
public:
	virtual void func1()
	{
		cout << "C::func1" << endl;
	}

	virtual void func5()
	{
		cout << "C::func5" << endl;
	}
public:
	int _c;
};

class D : public B, public C
{
public:
	virtual void func1()
	{
		cout << "D::func1" << endl;
	}

	virtual void func2()
	{
		cout << "D::func2" << endl;
	}
public:
	int _d = 1;
};

int main()
{
	D d;

	return 0;
}

先来看一个问题,D里有几张虚表?

答案是两张,这种情况就跟普通的多继承没两样。

改成虚拟菱形继承就不一样了。

此时有看起来有3个虚表,其实还是2个。菱形这块太复杂,我不分析了。

相关推荐
卡卡~~16 分钟前
“101计划”核心课程实践教材《数据实验结构指导-C++语言版》题目集
开发语言·c++·学习·算法
qq_4069810329 分钟前
大白话rust系列09 函数调用两次有什么错?
开发语言·python·rust
学逆向的38 分钟前
C 多文件开发
c语言·开发语言·网络安全
企业数字化笔记1 小时前
AI视频增强后画质怎么验收?插值基线、伪细节与帧间闪烁的检查方法
人工智能·算法·音视频
布吉岛的石头1 小时前
Java 程序员第 50 阶段3:数据工程:预训练语料清洗与去重
java·开发语言·人工智能·深度学习·transformer
benchmark_cc1 小时前
QuantDash 安装成功后,如何验证 Python 环境可以正常导入 SDK?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
学逆向的1 小时前
C 内存属性
c语言·开发语言·算法·网络安全
Zwawa1 小时前
一盏 LED 不够用了:让同一盏灯说出不同的话
c语言·单片机·嵌入式
lengxuenong2 小时前
树状数组 · 信息学学习手册1-求和3个模板
c++·学习·算法·青少年编程