
多态是C++面向对象三大特性之一多态分为两类
1. 静态多态:函数重载和运算符重载属于静态多态,复用函数名·2.动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别:
·静态多态的函数地址早绑定–编译阶段确定函数地址·动态多态的函数地址晚绑定–运行阶段确定函数地址下面通过案例进行讲解多态
动态多态满足条件
1、有继承关系
2、子类重写父类的虚函数动态多态使用
父类的指针或者引用执行子类对象重写:函数返回值类型函数名参数列表完全—致称为重写
静态多态代码:
- #include
- using namespace std;
- class dongwu {
- public:
- void speak() {
- cout << "动物叫" << endl;
- }
- };
-
- class cat :public dongwu {
- void speak() {
- cout << "猫叫" << endl;
- }
- };
- //早绑定,编译阶段就确定函数的地址
-
- void speak(dongwu& p) {
- p.speak();
- }
- void fun() {
- cat p;
- speak(p);
- }
- int main() {
- fun();
- cat p;
- //发生隐式转换,只能把儿子转为父亲,退化
- dongwu m = p;
- m.speak();
- return 0;
- }
注意转化,以及早绑定的特性是执行当前的类型的函数,不执行儿子的函数
动态动态代码:
- #include
- using namespace std;
- class dongwu {
- public:
- //virtual虚函数关键字
- virtual void speak() {
- cout << "动物叫" << endl;
- }
- };
-
- class cat :public dongwu {
- //子类的virtual可加可不加
- virtual void speak() {
- cout << "猫叫" << endl;
- }
- };
-
- //晚绑定,执行子类的函数
- void speak(dongwu& p) {
- p.speak();
- }
- void fun() {
- cat p;
- speak(p);
- }
- int main() {
- fun();
-
- return 0;
- }

我们先看以下代码:
- #include
- using namespace std;
- class father1 {
- public:
- void speak() {
- cout << "动物叫" << endl;
- }
- };
- class father2 {
- public:
- virtual void speak() {
- cout << "动物叫" << endl;
- }
- };
- int main() {
- cout << sizeof(father1) << endl;
- cout << sizeof(father2) << endl;
-
- return 0;
- }

当类的成员函数加入虚函数关键字后,会发现类的大小发生了改变。此时类的内部结构。此时类的内部会多一个指针虚函数(表)指针,虚函数指针指向虚函数表,虚函数表中存储虚函数的入口地址。
那么当派生类继承基类后,如果成员函数没有重名,那么会完全继承父类的结构。

但是当派生类,重写基函数的虚函数时,派生类中的虚函数表会发生改变,此时虚函数表指向派生类的虚函数,基类的虚函数被覆盖。

此时,我们有派生类隐式转换为基类时,虚函数表中的内容并不改变,此时调用虚函数,执行的是派生类的虚函数。
1、组织结构清晰
2、可读性强
3、对于前期和后期扩展以及维护性高
普通计算机类:
- #include
- using namespace std;
- class jisuanqi {
- public:
- int a, b;
- int jisuan(string fu) {
- if (fu == "+") {
- return a + b;
- }
- else if (fu == "-") {
- return a - b;
- }
- else if (fu == "*") {
- return a * b;
- }
- }
- };
- void fun() {
- jisuanqi q;
- q.a = 200;
- q.b = 100;
- cout << q.a << " - " << q.b << " = " << q.jisuan("-") << endl;
- cout << q.a << " + " << q.b << " = " << q.jisuan("+") << endl;
- cout << q.a << " * " << q.b << " = " << q.jisuan("*") << endl;
-
- }
- int main() {
- fun();
- return 0;
- }
多态计算机类:
- #include
- using namespace std;
- class jisuanqi {
- public:
- int a;
- int b;
- virtual int jisuan() {
- return 0;
- }
- };
-
- class add :public jisuanqi {
- virtual int jisuan() {
- return a+b;
- }
- };
-
- class jian :public jisuanqi {
- virtual int jisuan() {
- return a - b;
- }
- };
-
- class cheng:public jisuanqi {
- virtual int jisuan() {
- return a * b;
- }
- };
-
- void fun() {
- jisuanqi* p = new add;
- p->a = 200;
- p->b = 100;
- cout << p->a << " + " << p->b << " = " << p->jisuan()<
- delete p;
-
- p = new jian;
- p->a = 200;
- p->b = 100;
- cout << p->a << " - " << p->b << " = " << p->jisuan()<
- delete p;
-
-
- p = new cheng;
- p->a = 200;
- p->b = 100;
- cout << p->a << " * " << p->b << " = " << p->jisuan()<
- delete p;
- }
- int main() {
- fun();
- return 0;
- }
四.纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容因此可以将虚函数改为纯虚函数。当类中有了纯虚函数,这个类也称为抽象类
纯虚函数语法: virtual 返回值类型 函数名︰(参数列表)= 0 ;
抽象类特点:
·无法实例化对象
·子类必须重写抽象类中的纯虚函数,否则也属于抽象类
代码:
- #include
- using namespace std;
-
- class father {
- public:
- //纯虚函数
- virtual void fun() = 0;
- };
-
-
- class son :public father{
- public:
- void fun() {
- cout << "我是sond" << endl;
- }
- };
-
- void fun() {
- //多态f必须是指针或者引用
- //father f; 报错不可实例化
- father* f = new son;
- f->fun();
- }
- int main() {
- fun();
- return 0;
- }
案例制作饮品:
- #include
- using namespace std;
- class father {
- public:
- virtual void zhushui() = 0;
- virtual void chongpao() = 0;
- virtual void daoru() = 0;
- virtual void jialiao() = 0;
- void fun() {
- zhushui();
- chongpao();
- daoru();
- jialiao();
- }
- };
-
- class tea :public father{
- void zhushui() {
- cout << "煮山泉水" << endl;
- };
- void chongpao() {
- cout << "冲茶" << endl;
- };
- void daoru() {
- cout << "倒入茶杯中" << endl;
- };
- void jialiao() {
- cout << "加入枸杞" << endl;
- };
- };
-
- class kafei : public father{
- void zhushui() {
- cout << "煮水" << endl;
- };
- void chongpao() {
- cout << "冲咖啡" << endl;
- };
- void daoru() {
- cout << "倒入咖啡杯中" << endl;
- };
- void jialiao() {
- cout << "加入奶和糖" << endl;
- };
- };
- //函数接口
- void fun(father* p) {
- p->fun();
- delete p;
- }
- int main() {
- fun(new tea);
- cout << "----------" << endl;
- fun(new kafei);
- return 0;
- }

五. 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:
将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
·可以解决父类指针释放子类对象·都需要有具体的函数实现
虚析构和纯虚析构区别:
·如果是纯虚析构,该类属于抽象类,无法实例化对象
代码:
- #include
- using namespace std;
- class father {
- public:
- //纯虚函数
- virtual void fun() =0;
- father() {
- cout << "father构造函数" << endl;
- }
- ~father() {
- cout << "father析构函数" << endl;
- }
- };
-
- class son :public father {
- public:
- //堆区开辟数据
- son(int age) {
- cout << "son构造函数" << endl;
- this->age = new int(age);
- }
-
- ~son() {
- cout << "son析构函数" << endl;
- if (this->age != NULL) {
- delete age;
- age = NULL;
- }
- }
- void fun() {
- cout << *age<< "son的fun函数调用" << endl;
- }
- int* age;
- };
- void fun() {
-
- father* p = new son(21);
- delete p;
- }
- int main() {
- fun();
- return 0;
- }

如图,当发生多态时,基类并不会调用子类的析构函数,当子类中含有堆区开辟的空间时。会造成内存泄漏。此时需要虚析构或纯虚析构来解决。
虚析构代码:
- #include
- using namespace std;
- class father {
- public:
- //纯虚函数
- virtual void fun() =0;
- father() {
- cout << "father构造函数" << endl;
- }
- virtual ~father() {
- cout << "father析构函数" << endl;
- }
- };
-
- class son :public father {
- public:
- //堆区开辟数据
- son(int age) {
- cout << "son构造函数" << endl;
- this->age = new int(age);
- }
-
- ~son() {
- cout << "son析构函数" << endl;
- if (this->age != NULL) {
- delete age;
- age = NULL;
- }
- }
- void fun() {
- cout << *age<< "son的fun函数调用" << endl;
- }
- int* age;
- };
- void fun() {
-
- father* p = new son(21);
- delete p;
- }
- int main() {
- fun();
- return 0;
- }
纯虚析构:
- #include
- using namespace std;
- class father {
- public:
- //纯虚函数
- virtual void fun() =0;
- father() {
- cout << "father构造函数" << endl;
- }
- virtual ~father() = 0;
- };
- //纯虚函数必须
- father::~father()
- {
- cout << "father析构函数" << endl;
- }
-
- class son :public father {
- public:
- //堆区开辟数据
- son(int age) {
- cout << "son构造函数" << endl;
- this->age = new int(age);
- }
-
- ~son() {
- cout << "son析构函数" << endl;
- if (this->age != NULL) {
- delete age;
- age = NULL;
- }
- }
- void fun() {
- cout << *age<< "son的fun函数调用" << endl;
- }
- int* age;
- };
- void fun() {
-
- father* p = new son(21);
- delete p;
- }
- int main() {
- fun();
- return 0;
- }
案例计算机
- #include
- using namespace std;
-
- class CPU {
- public:
- //纯虚函数
- virtual void func() = 0;
- };
-
- class Memory_Module {
- public:
- //纯虚函数
- virtual void func() = 0;
- };
-
- class Graphics_card {
- public:
- //纯虚函数
- virtual void func() = 0;
- };
-
-
- class CPU_intel : public CPU {
- public:
- void func() {
- cout << "intel的CPU工作" << endl;
- }
- };
-
- class Graphics_card_intel : public Graphics_card {
- public:
- void func() {
- cout << "intel的显卡工作" << endl;
- }
- };
-
-
-
- class Memory_Module_intel : public Memory_Module {
- public:
- void func() {
- cout << "intel的内存条工作" << endl;
- }
- };
-
-
-
- class CPU_lenovo: public CPU {
- public:
- void func() {
- cout << "联想的CPU工作" << endl;
- }
- };
-
- class Graphics_card_lenovo : public Graphics_card {
- public:
- void func() {
- cout << "联想的显卡工作" << endl;
- }
- };
- class Memory_Module_lenovo : public Memory_Module {
- public:
- void func() {
- cout << "联想的内存条工作" << endl;
- }
- };
- class computer {
- public:
- //当传入的是子类时发生多态
- computer() {};
- computer(CPU* CPU , Memory_Module* m, Graphics_card* g) {
- this->cpu = CPU;
- this->m = m;
- this->g = g;
- }
- void work() {
- cpu->func();
- m->func();
- g->func();
- }
- private:
- CPU* cpu;
- Memory_Module* m;
- Graphics_card* g;
- };
-
- void fun() {
- CPU_lenovo* c1 = new CPU_lenovo;
- CPU_intel* c2 = new CPU_intel;
- Graphics_card_intel* g1 = new Graphics_card_intel;
- Graphics_card_lenovo* g2 = new Graphics_card_lenovo;
- Memory_Module_intel* m1 = new Memory_Module_intel;
- Memory_Module_lenovo* m2 = new Memory_Module_lenovo;
-
- cout << "第一台电脑" << endl;
- computer* com = new computer(c1,m1,g1);
- com->work();
- cout << "********************************" << endl;
- cout << "第二台电脑" << endl;
- computer* com1 = new computer(c2, m2, g2);
-
- com1->work();
- }
- int main() {
- fun();
- return 0;
- }

-
相关阅读:
ftp多用户多目录配置
windows环境下mongodb 5.0.9分片集群环境搭建
pgbouncer 使用
猿创征文 第二季| #「笔耕不辍」--生命不息,写作不止#
【第29例】IPD体系进阶:PL-TMT 产品线技术管理团队
手把手怎么把照片修复高清,p图小白也能轻松上手
leetcode42. 接雨水
安装使用RocketMQ一套保姆全教程-最快完成SpringBoot使用消息队列demo
判断是否工作在docker环境
猿创征文|基于STM32设计的物联网熏艾空气消毒装置(STM32+华为云IOT)
-
原文地址:https://blog.csdn.net/m0_73731708/article/details/132927521