[C++] 多态(下) -- 多态原理 -- 动静态绑定

这篇具有很好参考价值的文章主要介绍了[C++] 多态(下) -- 多态原理 -- 动静态绑定。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

上一篇文章我们了解了虚函数表,虚函数表指针,本篇文章我们来了解多态的底层原理,更好的理解多态的机制。
[C++] 多态(上) – 抽象类、虚函数、虚函数表

1、多态原理

下面这段代码中,Func函数传Person调用的Person::BuyTicket,传Student调用的是Student::BuyTicket,这就是多态调用,但是这里我们并不知道原理是什么,接下来我们就来了解一下原理。

class Person 
{
public:
	virtual void BuyTicket() 
	{ 
		cout << "买票-全价" << endl; 
	}
};
class Student : public Person 
{
public:
	virtual void BuyTicket() 
	{ 
		cout << "买票-半价" << endl; 
	}
};
void Func(Person* p)
{
	p->BuyTicket();
}
int main()
{
	Person p;
	Func(&p);
	Student s;
	Func(&s);

	return 0;
}

[C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

  1. 观察监视窗口我们看到,p是指向p对象时,p->BuyTicket在p的虚表中找到虚函数是Person::BuyTicket。
  2. 观察监视窗口我们看到,p是指向s对象时,p->BuyTicket在s的虚表中找到虚函数是Student::BuyTicket。从Student中切片出来的父类,call BuyTicket的地址已经发生了改变。
  3. 这样就实现出了不同对象去完成同一行为时,展现出不同的形态。
  4. 反过来思考我们要达到多态,有两个条件:1、一个是虚函数覆盖;2、一个是对象的指针或引用调用虚函数。
  5. 再通过下面的汇编代码分析,看出满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。
    多态调用:运行时,去虚表中找到地址去调用函数
    普通调用:编译时,确定函数地址
    [C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

2、动态绑定和静态绑定

  1. 静态绑定又称为前期绑定(早绑定),在 程序编译期间确定了程序的行为,也称为静态多态,比如:函数重载;
  2. 动态绑定又称后期绑定(晚绑定),是在 程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态;
  3. 上面的买票汇编就解释了什么是具体的动态绑定和静态绑定。

3、单继承和多继承关系的虚函数表

3.1 单继承中的虚函数表

class Base
{
public:
	virtual void func1()
	{
		cout << "Base::func1" << endl;
	}
	virtual void func2()
	{
		cout << "Base::func2" << endl;
	}
private:
	int _a;
};
class Derive :public Base {
public:
	virtual void func1() 
	{ 
		cout << "Derive::func1" << endl; 
	}
	virtual void func3() 
	{ 
		cout << "Derive::func3" << endl; 
	}
	virtual void func4() 
	{ 
		cout << "Derive::func4" << endl; 
	}
private:
	int b;
};
int main()
{
	Base b;
	Derive d;

	return 0;
}

[C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

观察上图中的监视窗口中我们发现看不见func3和func4。这里是编译器的监视窗口故意隐藏了这两个函数,也可以认为是他的一个小bug。那么我们如何查看d的虚表呢?我们写一段代码来将需表中的虚函数打印出来。

代码思路: 取出b、d对象的头4bytes,就是虚表的指针,前面我们说了虚函数表本质是一个存虚函数指针的指针数组,这个数组最后面放了一个nullptr。
1.先取b的地址,强转成一个int的指针;
2.再解引用取值,就取到了b对象头4bytes的值,这个值就是指向虚表的指针;
3.再强转成VFPTR
,因为虚表就是一个存VFPTR类型(虚函数指针类型)的数组;
4.虚表指针传递给PrintVTable进行打印虚表;
5.需要说明的是这个打印虚表的代码经常会崩溃,因为编译器有时对虚表的处理不干净,虚表最后面没有放nullptr,导致越界,这是编译器的问题。我们只需要点目录栏的-生成-清理解决方案,再编译就好了。

typedef void(*VFPTR) (); // 重命名函数指针
void PrintVTable(VFPTR vTable[])
{
	// 依次取虚表中的虚函数指针打印并调用。调用就可以看出存的是哪个函数
	cout << " 虚表地址->" << vTable << endl;
	for (int i = 0; vTable[i] != nullptr; ++i)
	{
		printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);
		VFPTR f = vTable[i];
		f();
	}
	cout << endl;
}
int main()
{
	Base b;
	Derive d;

	VFPTR* vTableb = (VFPTR*)(*(int*)&b);
	PrintVTable(vTableb);
	
	VFPTR* vTabled = (VFPTR*)(*(int*)&d);
	PrintVTable(vTabled);
	
	return 0;
}

[C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

5.2 多继承中的虚函数表

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;
};

typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[])
{
	cout << " 虚表地址>" << vTable << endl;
	for (int i = 0; vTable[i] != nullptr; ++i)
	{
		printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);
		VFPTR f = vTable[i];
		f();
	}
	cout << endl;
}
int main()
{
	Derive d;

	VFPTR* vTableb1 = (VFPTR*)(*(int*)&d);
	PrintVTable(vTableb1);

	VFPTR* vTableb2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1)));
	PrintVTable(vTableb2);

	return 0;
}

观察下图可以看出:多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中。
[C++] 多态(下) -- 多态原理 -- 动静态绑定,C++,c++

最后菱形继承、菱形虚拟继承就不再,因为正常情况下很少用,这里就不再多讲了。文章来源地址https://www.toymoban.com/news/detail-762975.html

到了这里,关于[C++] 多态(下) -- 多态原理 -- 动静态绑定的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 思科交换机端口动态、静态安全绑定案例

    1、该端口不是聚合端口 2、该端口是access模式 3、配置前要关闭该端口(shutdown) 违规操作:(没有加入端口安全的PC机做一下操作) 1、给没有加入到安全端口的PC进行IP地址配置(增加1次) 2、进行ping操作第一次增加5次,下一次增加4次 查看当前访问过得IP地址信息 Switch(

    2023年04月08日
    浏览(28)
  • Nmcli — 配置静态IP 、Team网卡绑定 、桥接

    目录 一、Nmcli — 静态IP的配置 1.网卡的配置文件 2.在命令行输入命令 二 、Team网卡绑定的实验 1.Team网络组的模式,及其配置的示例文件 2.实验过程  (1)、创建逻辑接口,名称为team0,且使用主备模式 (2)、添加多个从设备(从)  (3)、激活设备 (4)、查看网卡的状态

    2024年02月09日
    浏览(44)
  • 华为(huawei)三层交换的ip绑定mac地址配置示例(静态及动态dhcp绑定)

    在某些需要较高网络安全性的单位中,为了网络安全的考虑有时候会采取IP绑定mac地址的这类安全措施。一方面防止内部人员擅自改动接入IP(可能导致IP冲突或者联不上网络),另一方面也可以防止ARP欺骗。 拓扑图 拓扑说明: HX_SW为核心交换机,SW1和SW2分别为业务网段和服

    2024年02月05日
    浏览(31)
  • DHCP静态分配IP地址、IP-MAC绑定、静态ARP有哪些区别?

    DHCP静态分配IP地址、IP-MAC绑定、静态ARP这三个功能都涉及到IP地址和MAC地址的对应关系,但其应用场景及实现的功能有所不同,如表所示: 原文地址https://support.huawei.com/enterprise/zh/knowledge/EKB1000052241

    2024年02月15日
    浏览(30)
  • C++修炼之路之多态---多态的原理(虚函数表)

    目录 一:多态的原理  1.虚函数表  2.原理分析 3.对于虚表存在哪里的探讨 4.对于是不是所有的虚函数都要存进虚函数表的探讨 二:多继承中的虚函数表 三:常见的问答题  接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧  接上篇的多态的介绍后,接下来介绍

    2024年04月26日
    浏览(26)
  • C++中的多态你真的了解吗?多态原理全面具体讲解

    目录 1. 多态的概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数 2.3 虚函数的重写 2.4 C++11 override 和 final 2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 4. 多态的原理 4.1 虚函数表 4.2多态的原理 4.3 动态绑定与静态绑定 5. 单继承和多继承关系中的虚函数表

    2024年02月04日
    浏览(24)
  • 华为交换机端口安全Port-Security策略应用(静态绑定)

    交换机静态端口绑定 实验开始 先配置 pc机ip等基本信息 并测试连通性(已通信) 此时交换机没有做任何配置 所以只进行数据转发功能 进入交换机,静态绑定pc1的IP地址和mac地址 此时还需注意的一点是交换机显示和识别的mac地址的形式与pc机上表现的形式有所不同 “0000-0000-000

    2024年01月20日
    浏览(28)
  • C++中多态的原理

    上篇讲解了多态的原理,这篇文章来详细讲解一下多态的原理。 这里有一道常考笔试题:sizeof(Base)是多少? 为什么不是8? 可以调试带大家看一下。 仔细看,对象的头部多了一个指针。 这个指针叫做虚函数表指针。 上面不重要,重要的是下面的东西,多态的原理。 这个指

    2024年02月04日
    浏览(34)
  • 【C++】多态及原理

    1.多态的概念 多态,顾名思义就是多种状态, 具体点就是去完成某种行为,但是通过不同的对象去完成某种行为都会产生不同的状态,这就是多态 比如买票这个行为。当 普通人 买票时,是全价买票; 学生 买票时,是半价买票; 军人 买票时是优 先买票。 这就是不同的对象

    2024年02月16日
    浏览(24)
  • 【C++】详解多态的底层原理

    上一篇文章我们学习了多态的语法,想必大家都会有很多疑问,这篇文章,我们就来带大家看看多态是如何实现的,它底层的原理是怎样的… 需要声明的,本文中的代码及解释都是在vs2022下的x86程序中,涉及的指针都是4bytes。 如果要其他平台下,部分代码需要改动。比如:

    2024年02月16日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包