多态的目标:一种调用语句有多种不同的表现形态
根据实际的对象类型来判断重写函数的调用
如果父类指针指向的是父类对象则调用父类中定义的函数
如果父类指针指向的是子类对象则调用子类中定义的重写函数
实现的手段:通过虚函数来实现(下面会具体介绍)
虚函数:在函数声明的没钱加virtual 关键字,该函数就变为虚函数。(内联函数、静态函数、构造函数不能是虚函数)
多态实现的条件:
1、要有继承
2、要有虚函数重写
3、用基类指针指向派生类对象
具体事例和注释:
#include <iostream>
using namespace std;
//基类
class Animal
{
public:
void eat()
{
cout << "动物吃饭" << endl;
}
//虚函数
virtual void sleep()
{
cout << "动物睡觉" <<endl;
}
};
class Cat:public Animal
{
public:
//函数重定义
void eat()
{
cout << "猫吃鱼" << endl;
}
//虚函数的重定义 =====> 函数重写
void sleep()
{
cout << "猫睡觉" << endl;
}
};
class Fish:public Animal
{
public:
//函数重定义
void eat()
{
cout << "鱼吃虾" << endl;
}
//虚函数的重定义 =====> 函数重写
void sleep()
{
cout << "鱼睁眼睡觉" << endl;
}
};
//基类指针
//期望做的事:同样的调用语句
//1、当基类指针指向基类对象的时候,调用基类自己的成员函数
//2、当基类指针指向派生类对象的时候,调用派生类的同名成员函数
//======》多态:一种调用语句有多种不同的表现形态
//======》实现:通过 虚函数 来实现 ------》在函数声明前加 virtual 关键字,该函数就变为虚函数
//预处理、编译、汇编、连接
void func(Animal *pa)
{
//指针的行为受限于指针的类型
//pa是Animal类型,所以只能执行Animal 内部的方法
//编译器执行流程
//1、判断 pa 的类型----->Animal类型
//2、判断 eat()函数类型 ----->是个普通函数
//3、结果:因为是普通函数,所以按照指针类型调用,
//由1知识Animal类型,所以直接调用Animal::eat()
//上述流程是在编译期间就已经知道如何处理如何运行----->这种就叫做静态联编 (早期绑定)
pa->eat();
//1、判断 pa 的类型----->Animal类型
//2、判断 sleep()函数类型 ----->是个 虚函数
//3、结果:因为是虚函数,所以编译器不知道调用谁的函数
//---->会通过某种机制,找到 最终需要调用的函数(和传过来的对象有关)
//上述这种在编译期间无法知道具体如何处理、
//需要在 运行的时候 根据传入的对象才能确定具体调用------>动态联编 迟绑定
pa->sleep();
}
int main()
{
Animal a;
Cat c;
Fish f;
func(&a);
cout << "-------------" << endl;
func(&c);
cout << "-------------" << endl;
func(&f);
cout << "-------------" << endl;
return 0;
}
多态的原理
#include <iostream>
using namespace std;
class Animal
{
public:
//类中有虚函数则,类的内存模型中,会有一个虚函数指针(vfptr)
//用来指向当前类的需函数表,该指针排列在对象的开始部分
//虚函数指针(vfptr) 要优先于 虚基类指针(vbptr)
//基类中有vfptr指针则 派生类中也会有,即基类中的虚函数,派生类中同名的函数也是虚函数()
virtual void eat()
{
cout << "动物吃饭" << endl;
}
void sleep()
{
cout << "动物睡觉" << endl;
}
private:
int a;
};
class Cat:public Animal
{
public:
virtual void eat()
{
cout << "猫吃饭" << endl;
}
void sleep()
{
cout << "猫睡觉" << endl;
}
private:
int b;
};
void func(Animal *pa)//用基类指针接受派生类对象地址
{
/*多态原理:
如何确定传过来的对象类型?======》如何找到传过来的对象的相应函数?
多态的实现依靠虚函数====》虚函数做了什么?
1、根据传过来的对象找到对应的类,通过基类指针 找到该类的虚函数指针
2、通过虚函数指针找到 虚函数表
3、在虚函数表中找到 需要执行的函数
*/
pa->eat(); //pa->vfptr->eat();
pa->sleep();
}
int main()
{
cout << sizeof(Animal) << endl;
cout << sizeof(Cat) << endl;
Animal a;
Cat c, c1, c2;//&c == &c1 == &c2,有虚函数的类会有一张虚函数表
//该类对象模型中最上面会有一个虚函数指针,该指针指向自身类的虚函数表
//虚函数表具有唯一性,一个类只有一张虚函数表
func(&a);
func(&c);
return 0;
}