一、多态的概念
同一种事物在不同场景下的多种状态;
多态的含义:
如果基类的指针指向基类的对象,则函数调用基类中的虚函数;
如果基类的指针指向派生类的对象,则函数调用派生类中的虚函数。
二、多态的分类
静态多态:在程序编译期间已经确定函数的行为;
形成机制:函数重载、泛型编程;
动态多态:在程序运行期间确定函数的行为(具体调用哪个函数);
形成机制:虚函数+重写+基类引用/指针引用
三、动态多态的条件
(1)基类中必须包含虚函数,并且派生类一定要对基类中的虚函数进行重写;
(2)通过基类对象的指针或引用来调用虚函数。
四、实现多态的例子
class Base
{
public:
virtual void FunTest1(int _iTest)
{
cout << "Base::FunTest1()" << endl;
}
void FunTest2(int _iTest)
{
cout << "Base::FunTest2()" << endl;
}
virtual void FunTest3(int _iTset1)
{
cout << "Base::FunTest3()" << endl;
}
virtual void FunTest4(int _iTest)
{
cout << "Base::FunTest4()" << endl;
}
};
class Derived :public Base
{
public:
virtual void FunTest1(int _iTest)
{
cout << "Derived::FunTest1()" << endl;
}
virtual void FunTest2(int _iTest)
{
cout << "Derived::FunTest2()" << endl;
}
void FunTest3(int _iTest)
{
cout << "Derived::FunTest3()" << endl;
}
virtual void FunTest4(int _iTest1, int _iTest2)
{
cout << "Derived::FunTest4()" << endl;
}
};
void TestVirtual(Base& b)
{
b.FunTest1(0);
b.FunTest2(0);
b.FunTest3(0);
b.FunTest4(0);
//b.FunTest4(0, 0);
}
int main()
{
//TestWashRoom();
Base b;
Derived d;
TestVirtual(b);
TestVirtual(d);
system("pause");
return 0;
}
五、重写的条件
(1)基类的函数都要是虚函数;
(2)基类和派生类的函数原型必须一致(函数返回值、函数名、函数参数列表);
(3)派生类中的函数可以是虚函数,也可以是普通函数。
特例:
(1)协变:基类的虚函数必须返回基类对象指针或引用,派生类的虚函数必须返回派生类对象的指针或引用。
(2)析构函数:如果析构函数是虚拟函数,也能构成重写。
六、动态多态实现原理
(1)编译器在带有虚函数的类背后维护了一张虚表(虚函数的入口地址);
(2)虚函数的调用原理(通过基类的指针或引用调用虚函数)
·从指针所指向对象(基类/派生类)前4个字节中取虚表的地址;
·传递参数(this + 当前虚函数的参数);
·根据从对象前4个字节取到的虚表的地址取对象的虚函数;
·调用虚函数。
对象模型:带有虚函数的类比普通类多4个字节。
基类:将类中的虚函数按照其在基类中出现的先后次序在虚表中存放;
派生类(单继承):
(1)将基类的虚表拷贝到派生类的虚表中;
(2)如果派生类重写了基类中的某个虚函数,将派生类中虚表相同偏移量位置的基类虚函数替换为派生类自己的虚函数;
(3)将派生类自己新增的虚函数按照其在派生类中的声明次序f放置到虚表的最后。
七、不同继承模式下对象的模型(带有虚函数)
·派生类的大小;
`定义派生类对象,到内存中确认对象的模型;
·确认虚表。