关注“想成为程序员的我”,每天都会发表编程标题
多态性是一种魔法功能,可以将代码的重复利用率提高一个等级。
首先,让我们来看看关键字virtual。 这是魔法关键词。 首先,让我们看看这个关键字有什么功能
有两个a、b、b类的虚拟继承a
a类
b类
函数测试
b存储器结构
程序的执行结果
由上可知,b类的大小为28字节,但a类和b类的成员加起来也是24字节,多有4个字节的地址。 让我跟进一下地址
这是一个偏移量表,前4个字节表示相对于自己的偏移量,最后4个字节表示相对于基类的偏移量。 因为这里使用的是十六进制数,所以表示相对于基类有16字节的偏移。 也就是说,添加关键字virtual时,类成员将增加4个字节的指针以存储偏移表。 偏移表中的指针是指仅在类和类之间存在虚继承时出现的指针。
在钻石继承中加入虚拟继承后,结构发生了变化,有4个类ABCD、b和c虚拟继承a、d继承b和c
执行测试函数
函数测试
执行结果
d的存储器结构
从内存结构可以看出,a类的成员是d的最后几个字节,按继承顺序是b类、c类、d类和a类的成员,并且在b类和c类的成员之前有一个指向偏移表的指针
b类虚拟指针指向地址
c类虚拟指针指向地址
b类的前4个字节是对自己的偏移,最后4个字节是对a类的偏移
c类的前4个字节是对自己的偏移,最后4个字节是对a类的偏移
这样可以节省a类所占的空间,但增加虚拟表的大小,d类调用的a类成员不会提出异议。
一旦了解了virtual关键字是创建虚拟表来处理事情,就可以知道它的多态性了。
首先需要知道对象的类型
静态类型:对象声明时的类型是在编译时确定的
动态类型:当前指向的对象的类型在运行时确定
因此,多态性有静态多态性(函数重载、通用编程)、动态多态性)、虚函数)两种。
静态多态性在编译器编译期间完成。 编译器可以根据函数参数的类型确定需要调用哪些函数。 如果有对应的函数就调用,如果没有就发生编译错误。
多态性。 使用virtual关键字限定类的成员函数,指示该函数是虚函数。 派生类需要重新实现,编译器实现动态绑定。
动态绑定条件:必须是虚函数,从基类类型的引用或指针调用虚函数。
这里必须在继承体系下,理解同名函数之间的关系
重载:在同一范围内,函数名称相同,参数不同,不要求返回值
重写(覆盖):在不同的作用域(基类和派生类),函数名相同,参数相同,返回值相同(协变例外:该函数,父类中返回父类的指针或引用;子类中返回子类的指针或引用),基类函数必须有virtual关键字,访问修饰符可以不同重定义(隐藏):在不同的作用域中(基类和派生类),函数名相同,在基类和派生类中只要不构成重写就是重定义。
了解完后我们再来了解一下纯虚函数,在成员函数的形参后面写上=0,则便是成员函数为程序函数,包含纯虚函数的类叫做抽象类,抽象类不能实例化对象,纯虚函数在派生类中重新定义后,派生类才能实例化出对象。
接下来我们来研究一下多态的对象模型,编写测试函数和测试类
我们将B类成员b强制转换成A类的成员,实现了动态多态,b的静态类型是B类,动态类型是A类,所以在控制台上会打印出fun函数的输出内容。
我们来分析一下b类的内存结构,B类的成员在上,A类成员在下,中间用0来隔开(这个作用是小编猜想的,如果有路过的大神可以在留言区讨论一下)
跟进前4个字节我们可以看见是B类的虚函数表,由于B类特有的虚函数只有一个所以只有一个指针,即fun2重写父类的虚函数不计算在B类虚函数表中
接着的4个字节是偏移量表
由偏移量表可以知道该类距离类指针指向位置-4个字节,距离A类成员20个字节。
我们进入基类位置的前4个字节,发现他也是一个虚函数表,A类有两个虚函数,即fun和fun1
如果是菱形继承的话结构就会更为复杂,修改类,并写一个测试函数
从内存结构来说,最基类也就是A类的成员是在最下面的,它的头4个字节存放着虚函数表的指针,最开始按照继承的顺序,先是B类,后是C类,前4个字节都是虚函数表指针,后4个字节是偏移量表的指针,整体结构就是比菱形继承多了一个虚函数表的指针。
如果还有其他的问题,可以通过同样的方法去探索。
结束语:
如果喜欢这篇头条,一定要收藏哟^O^
点击关注,了解更多关于编程的知识^O^
如果有不懂的地方,可以留言,相互探讨,相互学习,共同进步^O^