**摘要:**本文围绕 C++ 多态的实现条件与底层原理展开,重点讲解虚函数重写、父类指针或引用指向子类对象这两个核心条件,并结合虚函数表与虚函数指针的机制,说明多态调用是如何被触发的。文中通过监视窗口示意图和完整演示代码,直观展示子类重写虚函数后,父类引用指向不同对象时调用对应函数的过程。
目录
s
一、多态实现条件
1、子类必须重写父类的虚函数
虚函数的重写由两个例外
1、协变:协变的要求是返回值可以不同,但必须是父类的指针或者引用
2、派生类重写虚函数时,可以不写 virtual,继承虚属性;写上可读性更好。
2、由父类的指针或者引用指向子类对象
原理:通过虚函数表 +虚函数指针触发多态调用条件,
包含虚函数的类都有自己的虚函数表 ,并且在对象内存中有虚函数表指针 指向自己的虚函数表,
当用父类的指针或者引用指向子类对象 时,父类的指针或者引用 通过虚函数表指针 找到子类的虚函数表,最后调用子类重写后的虚函数。
问题:为什么不能是子类的指针或者引用
多态的核心目标是:同一个调用入口(指针 / 引用),指向不同类型的对象时,能自动调用对应类型的函数
**原因是子类的指针或者引用指向子类对象时,不能指向父类时调用父类的虚函数(语法不支持,不符合继承语义),只能做到指向子类的虚函数。**而父类的指针或者引用天然可以指向父类对象,也可以指向子类对象,可以做到通过一个调用入口,指向不同对象时,能够调用对应类型的函数
二、多态的原理
1、子类重写父类的虚函数监视窗口
子类得到父类的虚函数表,重写的虚函数会覆盖父类的虚函数。如下图所示

2、父类的引用指向子类对象监视窗口
首先对象内存模型中,有指向虚函数表的指针 ,虚函数表指针 指向虚函数表 ,虚函数表 中存放的是虚函数的地址

当父类的引用p指向了父类对象,调用的是父类的虚函数。
当父类的引用p指向了子类对象,调用的是子类重写父类后的虚函数。

3、演示代码
class Person
{
public:
virtual void BuyTicket()
{
cout << "票价-全价" << endl;
}
virtual void func1()
{
cout << "Person::func1()" << endl;
}
virtual void func2()
{
cout << "Person::func2()" << endl;
}
private:
int _a=1;
};
class Student : public Person
{
public:
virtual void BuyTicket()
{
cout << "票价-半价" << endl;
}
private:
int _b=2;
};
void func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person p;
Student st;
func(p);
func(st);
}