目录
多态是C++面向对象三大特性之一
最核心的是---父类指针指向子类对象,产生多态
一个接口多个形态
多态分为两类:
1.静态多态:函数重载和运算符重载属于静态多态,复用函数名
2.动态多态:派生类和虚函数实现运行时多态
静态多态与动态多态的区别:
1.静态多态的函数地址早绑定,编译阶段确定函数地址;
2.动态多态的函数地址晚绑定,运行阶段确定函数地址;
多态满足的条件:
1.有继承关系
2.子类重写父类的虚函数,子类是否为虚函数都可以
实现的效果:
父类的指针或者引用可以指向子类对象,实现子类对象的函数
class animal
{
public:
virtual void print()
{
cout << "aiaimal-print 调用" << endl;
}
};
class cat :public animal
{
public:
void print()
{
cout << "cat-print 调用" << endl;
}
};
void Print(animal& animal1)
{
animal1.print();
}
void test()
{
cat cat1;
Print(cat1);
}
将父类的同名函数设置为虚函数以后,那么全局函数执行的函数地址就由确定变化为了不确定。
多态的原理
当没有使用虚函数技术的时候,父类含有一个成员函数(成员变量与成员函数分开存储,成员函数不属于类上,此时父类是一个空类,大小为1)
当引入虚函数的技术以后,父类的内部结构发生了变化-->父类内部有一个VFPTR(虚函数(表)指针),指向一个VFTABLE(虚函数表),表内存储着虚函数地址入口。
当子类重写同名函数,继承父类数据时,虚函数表内的信息就被子函数的虚函数地址入口信息覆盖
当父类引用或指针指向子类对象时,就会调用子类的函数。
多态的优点
1.代码组织结构清晰
2.可读性强
3.利于前期和后期的扩展和维护
C++开发中提倡利用多态去设计程序架构
感悟:刚开始学习多态时的形式:
父类与子类都有一个同名函数,父类是虚函数
【但是这个与同名函数调用不同,那个是需要作用域区分,这个是传参的问题】
使用方式:设置一个全局函数,传入父类的引用,但是在实际传参中,传的是子类的
函数运行的结果也是子类中的函数
后面学习过程中:
只要父类指针指向子类对象【要调用子类】
后--->该指针直接调用函数即可
//部分代码---
abstract_cacluator* ptr1 = new add;
abstract_cacluator* ptr2 = new sub;
ptr1->m_num1 = 100;
ptr2->m_num1 = 55;
ptr1->m_num2 = 55;
ptr2->m_num2 = 30;
cout << ptr1->m_num1 << " + " << ptr1->m_num2 << " = " << ptr1->get_resualt() << endl;
cout << ptr2->m_num1 << " - " << ptr2->m_num2 << " = " << ptr2->get_resualt() << endl;
这种情况下,用完记得销毁堆区空间
纯虚函数与抽象类
在多态中,父类中的虚函数的实现毫无意义,可以直接将虚函数设置为纯虚函数
语法-->virtual 返回值类型 函数名(函数参数列表)= 0 ;
当类中存在纯虚函数后,这个类称为抽象类
抽象类的特点:
1.抽象类不允许实例化对象
2.子类必须重写抽象类中的纯虚函数,否则子类也属于抽象类
多态案例--制造饮品
#include <iostream>
using namespace std;
class drinking
{
public:
//煮水
virtual void boil() = 0;
//冲泡
virtual void brew() = 0;
//倒入
virtual void pour() = 0;
//加入
virtual void putt() = 0;
//整合到一起
void makedrink()
{
boil();
brew();
pour();
putt();
}
};
class tea :public drinking
{
public:
//煮水
virtual void boil()
{
cout << "煮茶水" << endl;
}
//冲泡
virtual void brew()
{
cout << "冲泡茶水" << endl;
}
//倒入
virtual void pour()
{
cout << "倒入茶叶" << endl;
}
//加入
virtual void putt()
{
cout << "放入茶水作料" << endl;
}
};
class coffee :public drinking
{
public:
//煮水
virtual void boil()
{
cout << "煮咖啡水" << endl;
}
//冲泡
virtual void brew()
{
cout << "冲咖啡水" << endl;
}
//倒入
virtual void pour()
{
cout << "倒入咖啡" << endl;
}
//加入
virtual void putt()
{
cout << "放入咖啡作料" << endl;
}
};
void makedrink(drinking* drink)
{
drink->makedrink();
delete drink;
drink = NULL;
}
void test()
{
makedrink(new tea);
makedrink(new coffee);
}
int main()
{
test();
return 0;
}
父类-制作饮品里面有四个纯虚函数和一个整合函数
子类继承的时候,重写了纯虚函数,子类不是抽象类。同时也继承了整合函数
整合函数会调用自己类的其他函数【找到了正确的函数入口】