一、多态
常说的多态,是发生在类之间的多态
函数重载(静态多态/编译时多态)
类之间的多态(动态多态/运行时多态)
【1】前提
继承是多态的前提
虚函数
什么是多态:相同的代码,实现不同的功能
【2】函数重写(override)
- 必须有继承关系
- 父类中必须有虚函数
在子类中重写父类的虚函数就是函数重写的过程,可以实现多态
【3】虚函数(virtual)
只要基类中是虚函数,后面的所有子类中该函数都是虚函数
常规来说,在继承时,给父类中的函数加上virtual关键字,定义成一个虚函数,
在子类中,可以对父类中的虚函数进行函数重写(override)
只要有虚函数的类,都会有一个虚函数表和一个虚(函数表)指针
虚指针是指向虚函数表的指针;
虚函数表,存储所有的虚函数的信息
虚函数表:保存所有虚函数的入口地址,每一个包含虚函数的类都会有一张虚函数表,
如果发生继承关系,子类会先复制父类的虚函数表,如果子类对某个虚函数重写,就去更改虚函数表中,该函数的入口地址
虚函数表指针:指向虚函数表的指针,父类中有一个虚函数表指针,子类中的虚函数表指针是从父类中继承下来的虚函数表指针,指向子类的虚函数表(虚函数表指针存在类中的第一个位置)
【4】虚析构函数
由于实现多态,需要使用父类的指针,指向子类的空间,父类指针可以操作的空间,只有父类自己的部分,所以,在delete父类指针时,并不会释放调子类的空间
解决方法:给基类(父类)的析构函数前面加上virtual关键字,只要基类是虚析构函数,后面继承的所有子类都是虚析构函数,虚析构函数会引导父类的指针,释放掉子类的空间
#include <iostream>
using namespace std;
class Person
{
public:
string name;
virtual void play()
{
cout << "吃饭" << endl;
}
virtual void fun()
{
cout << "fun" << endl;
}
virtual ~Person()
{
cout << "Person的析构" << endl;
}
};
class Stu:public Person
{
int age;
public:
void play() //在子类中,对父类中的play进行函数重写
{
cout << "打游戏" << endl;
}
~Stu()
{
cout << "Stu的析构" << endl;
}
};
class S:public Stu
{
public:
void play()
{
cout << "第二次继承" << endl;
}
void fun()
{
cout << "fun的第二次继承" << endl;
}
};
int main()
{
//父类的指针,指向子类的空间,可以调用子类中重写的函数(多态的实现)
Person *p = new Stu;
p->Person::play();
delete p;
// p->play();
// Person *p1 = new S;
// p1->play(); //第二次继承
// p1->fun(); //fun的第二次继承
// Person *p2 = new Stu;
// p2->fun(); //
return 0;
}