首先要说明虚函数是用来实现函数重载的,而虚拟继承是用来解决从不同途径继承来的同一基类,会在子类中存在多份拷贝,浪费空间,并且产生二义性的问题(如果想要了解虚拟继承可以点这里https://blog.csdn.net/a15929748502/article/details/80898126)
上一篇已经和大家探索了虚函数基本的一些内容,这一篇我们来开始探索含有虚函数的类的对象模型
一.单继承
下面打出了如下代码
#include <iostream>
using namespace std;
class B
{
public :
int _b ;
virtual void FuncA()
{
cout << " ---------->B::FuncA ..." << endl;
}
virtual void FuncB()
{
cout << " ---------->B::FuncB ..." << endl;
}
};
class D : public B
{
public :
int _d;
virtual void FuncB()
{
cout << " ---------->D::FuncB ..." << endl;
}
virtual void FuncC()
{
cout << " ---------->D::FuncC ..." << endl;
}
};
typedef void (*Func)();
int main ()
{
B b;
D d;
b._b=1;
d._b=2;
d._d=3;
long **p=(long**)&b;
long **pd=(long**)&d;
cout << "B" << endl;
cout <<*((int*)&b) << endl;
((Func)p[0][0])();
((Func)p[0][1])();
cout <<*((int*)&b+1) << endl;
cout << "sizeof(B) = " << sizeof(B) << endl;
cout <<"---------------------------------------------------------" << endl;
cout << "D" << endl;
cout <<*((int*)&d) << endl;
((Func)pd[0][0])();
((Func)pd[0][1])();
((Func)pd[0][2])();
cout <<*((int*)&d+1) << endl;
cout <<*((int*)&d+2) << endl;
cout << "sizeof(D) = " << sizeof(D) << endl;
return 0;
}
打印一下结果
可以看出单继承的对象模型是这样的
也就是
总结:对于单一继承来说基类的对象大小:成员大小+4(虚表指针)
在基类虚表中:将类中的虚函数按照在类中生命的先后顺序添加在虚表里
而在单继承的派生类之中:(1)将基类虚函数表中的内容拷贝一份,(2)如果派生类重写了基类的某个虚函数,使派生类自己的虚函数替换派生类虚表中相同偏移量位置的基类虚函数(3)按照派生类特有的虚函数的声明次序将其增加到虚函数表的最后
这样就构成了虚函数特有的调用过程,通过这种重写和特有的调用机制达到了实现多态的目的。
究竟是怎样调用的呢,一下是虚函数的调用原理
1,从对象的前四个字节取虚表的地址
2,传递this指针
3,从虚表中取出对应的虚函数:虚表地址+偏移量
4,执行当前的虚函数
再回顾一下动态多态的实现条件:
1.基类中必须存在虚基类,派生类必须重写虚基类中的虚函数。
重写时应注意:基类里的将被重写的函数必须是虚函数,
积累和派生类的原型必须一抹一样(包括返回值,函数名,参数)
注意:协变(基类(派生类)虚函数返回基类(派生类)的指针或引用)和构造函数例外
2通过基类对象的指针或引用来调用虚函数。
是不是又加深了自己的理解呢
如果大家还有兴趣,就请大家关注我的下一篇,下一篇中我会把多继承的情况说给你听