环境:win10+vs2015
为什么派生类对基类的虚函数进行重写后,通过基类对象的指针或引用来调用该虚函数,就可以实现多态呢?我们来探究一下多态的调用原理吧!
1.多态的调用原理:
如下代码:
#include<string>
class Base
{
public:
virtual void TestFunc1()
{
cout << "Base::TestFunc1()" << endl;
}
virtual void TestFunc2()
{
cout << "Base::TestFunc2()" << endl;
}
virtual void TestFunc3()
{
cout << "Base::TestFunc3()" << endl;
}
int _b;
};
typedef void(*PVTF)();
//打印虚表
void Print(Base& b,string const& str)
{
cout << str << endl;
PVTF *pVTF = (PVTF*)*(int*)&b;
while (*pVTF)
{
(*pVTF)();
pVTF++;
}
cout << endl;
}
class Derived :public Base
{
public:
//新增TestFunc4
virtual void TestFunc4()
{
cout << "Derived::TestFunc4()" << endl;
}
//重写TestFunc2
virtual void TestFunc2()
{
cout << "Derived::TestFunc2()" << endl;
}
//重写TestFunc3
virtual void TestFunc3()
{
cout << "Derived::TestFunc3()" << endl;
}
//新增TestFunc5
virtual void TestFunc5()
{
cout << "Derived::TestFunc5()" << endl;
}
int _d;
};
int main()
{
cout << "Base类大小:"<<sizeof(Base) << endl;
cout <<"Derived类大小:" <<sizeof(Derived) << endl;
Base b;
b._b = 1;
Derived d;
d._b = 1;
d._d = 2;
Print(b,"Base VFT:");
Print(d,"Derived VFT:");
return 0;
}
结果如下图:
分析:
单继承:
基类Base的大小为:8
(1)基类Base对象模型:
基类的虚函数表:将基类的中的虚函数按照声明的次序依次添加到虚表中
派生类大小为:12
(2)派生类对象模型:
派生类的虚函数表:
a)将基类的虚函数表拷贝一份
b)如果派生类重写了基类中的某个虚函数,用派生类虚函数替代相同偏移量位置的基类虚函数
c)将派生类自己的新增加的虚函数添加到虚表的最后
(3)多态的调用原理:
a.从对象的前四个字节取出虚表的地址
b.传参(this+虚函数形参)
c.从虚表中取出虚函数地址
d.调用虚函数
2.不同继承模式下对象模型(带有虚函数)
(1)单继承
上面已经探究过了
(2)多继承
//带有虚函数的多继承场景下派生类的对象模型&派生类的虚表
class B1
{
public:
virtual void TestFunc1()
{
cout << "B1::TestFunc1" << endl;
}
virtual void TestFunc2()
{
cout << "B1::TestFunc2" << endl;
}
int _b1;
};
class B2
{
public:
virtual void TestFunc3()
{
cout << "B2::TestFunc3" << endl;
}
virtual void TestFunc4()
{
cout << "B2::TestFunc4" << endl;
}
int _b2;
};
class Derived :public B1, public B2
{
public:
virtual void TestFunc5()
{
cout << "D::TestFunc5" << endl;
}
virtual void TestFunc2()
{
cout << "D::TestFunc2" << endl;
}
virtual void TestFunc3()
{
cout << "D::TestFunc3" << endl;
}
virtual void TestFunc6()
{
cout << "D::TestFunc6" << endl;
}
int _d;
};
typedef void(*PVTF)();
//打印虚表
void Print(B1& b,string const& str)
{
cout << str <<endl;
PVTF *pVTF = (PVTF*)*(int*)&b;
while (*pVTF)
{
(*pVTF)();
pVTF++;
}
cout << endl;
}
void Print(B2 & b, string const& str)
{
cout << str << endl;
PVTF *pVTF = (PVTF*)*(int*)&b;
while (*pVTF)
{
(*pVTF)();
pVTF++;
}
cout << endl;
}
int main()
{
cout << sizeof(Derived) << endl;
Derived d;
d._b1 = 1;
d._b2 = 2;
d._d = 3;
B1& b1 = d;
B2& b2 = d;
Print(b1, "D VTF---->B1:");
Print(b2, "D VTF---->B2:");
return 0;
}
结果如下:
分析:
多继承模式下派生类的虚函数表:
a)将基类的虚函数表拷贝一份
b)如果派生类重写了基类中的某个虚函数,用派生类虚函数替代相同偏移量位置的基类虚函数
c)将派生类自己的新增加的虚函数添加到第一张虚表的最后
(3)菱形继承(如图)
如下代码:
#include <string>
class B
{
public:
virtual void TestFunc1()
{
cout << "B::TestFunc1" << endl;
}
virtual void TestFunc2()
{
cout << "B::TestFunc2" << endl;
}
int _b;
};
class C1 : public B
{
public:
//重写B中的TestFunc1
virtual void TestFunc1()
{
cout << "C1::TestFunc1" << endl;
}
//新增TestFunc3
virtual void TestFunc3()
{
cout << "C1::TestFunc3" << endl;
}
int _c1;
};
class C2 : public B
{
public:
//重写B中的TestFunc2
virtual void TestFunc2()
{
cout << "C2::TestFunc2" << endl;
}
//新增TestFunc4
virtual void TestFunc4()
{
cout << "C2::TestFunc4" << endl;
}
int _c2;
};
class D :public C1,public C2
{
public:
//重写C1中的TestFunc1
virtual void TestFunc1()
{
cout << "D::TestFunc1" << endl;
}
//重写C1中的TestFunc3
virtual void TestFunc3()
{
cout << "D::TestFunc3" << endl;
}
//重写C2中的TestFunc4
virtual void TestFunc4()
{
cout << "D::TestFunc4" << endl;
}
//新增TestFunc5
virtual void TestFunc5()
{
cout << "D::TestFunc5" << endl;
}
int _d;
};
typedef void(*PVTF)();
void Print(C1 & b, string const& str)
{
cout << str << endl;
PVTF *pVTF = (PVTF*)*(int*)&b;
while (*pVTF)
{
(*pVTF)();
pVTF++;
}
cout << endl;
}
void Print(C2 & b, string const& str)
{
cout << str << endl;
PVTF *pVTF = (PVTF*)*(int*)&b;
while (*pVTF)
{
(*pVTF)();
pVTF++;
}
cout << endl;
}
int main()
{
D d;
d.C1::_b = 1;
d.C2::_b = 2;
d._c1 = 3;
d._c2 = 4;
d._d = 5;
C1& c1 = d;
C2& c2 = d;
Print(c1, "D VTF--->C1");
Print(c2, "D VTF--->C2");
return 0;
}
结果:
分析: