多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 - 编译阶段确定函数地址
- 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
1 #include <iostream> 2 using namespace std; 3 //animal class 4 class animal 5 { 6 public: 7 //虚函数 8 virtual void speak() 9 { 10 cout << "动物在说话" << endl;//不加virtual就是早绑定,加了就是晚绑定 11 } 12 }; 13 //cat class 14 class cat : public animal 15 { 16 public: 17 //重写 函数返回值类型 函数名 参数列表 完全相同 18 void speak() 19 { 20 cout << "小猫在说话" << endl; 21 } 22 }; 23 //dog class 24 class dog : public animal 25 { 26 public: 27 void speak() 28 { 29 cout << "小狗在说话" << endl; 30 } 31 }; 32 //执行说话的函数 33 //地址早绑定 在编译阶段确定函数地址 34 //如果想执行让猫说话 那么这个函数地址就不能提前绑定 需要在运行阶段进行绑定,也就是地址晚绑定 35 36 //动态多态满足条件 37 //1.得有继承关系 38 //2.子类重写父类虚函数 39 40 //动态多态的使用 41 //父类的指针或引用 执行子类的对象 42 void dospeak(animal& Animal)//animal & Animalv= cat; 43 { 44 Animal.speak(); 45 } 46 void test01() 47 { 48 cat ca;//父类的引用指向子类对象 49 dospeak(ca); 50 dog dogg; 51 dospeak(dogg); 52 } 53 int main() 54 { 55 test01(); 56 }
多态原理剖析:
未重写时:
重写后:
总结:
多态满足条件
- 有继承关系
- 子类重写父类中的虚函数
多态使用条件
- 父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
多态案例一-计算器类
案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类
多态的优点:
- 代码组织结构清晰
- 可读性强
- 利于前期和后期的扩展以及维护
普通写法:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 class calculator 5 { 6 public: 7 int geresult(string oper) 8 { 9 if (oper == "+") 10 { 11 return n_num1 + n_num2; 12 } 13 else if (oper == "-") 14 { 15 return n_num1 - n_num2; 16 } 17 else if (oper == "*") 18 { 19 return n_num1 * n_num2; 20 } 21 else if (oper == "/") 22 { 23 return n_num1 / n_num2; 24 } 25 } 26 int n_num1;//操作数1 27 int n_num2;//操作数2 28 }; 29 void test01() 30 { 31 //创建计算器的对象 32 calculator c; 33 c.n_num1 = 10; 34 c.n_num2 = 10; 35 cout << c.n_num1 << "+" << c.n_num2 << "=" <<c.geresult("+") << endl; 36 cout << c.n_num1 << "-" << c.n_num2 << "=" << c.geresult("-") << endl; 37 cout << c.n_num1 << "*" << c.n_num2 << "=" << c.geresult("*") << endl; 38 cout << c.n_num1 << "/" << c.n_num2 << "=" << c.geresult("/") << endl; 39 } 40 int main() 41 { 42 test01(); 43 }
多态写计算器类
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 class calculator 5 { 6 public: 7 int geresult(string oper) 8 { 9 if (oper == "+") 10 { 11 return n_num1 + n_num2; 12 } 13 else if (oper == "-") 14 { 15 return n_num1 - n_num2; 16 } 17 else if (oper == "*") 18 { 19 return n_num1 * n_num2; 20 } 21 else if (oper == "/") 22 { 23 return n_num1 / n_num2; 24 } 25 //如果想拓展新功能,需求修改源码 26 //在真正的开发中 提倡开闭原则 27 //开闭原则 对拓展进行开放,对修改进行关闭 28 } 29 int n_num1;//操作数1 30 int n_num2;//操作数2 31 }; 32 //利用多态来实现计算器 33 // 多态好处 34 //1: 组织结构清晰 35 //2:可读性强 36 //3:对于前期和后期的维护性高 37 //实现计算器抽象类 38 class abstractcalculator 39 { 40 public: 41 virtual int getresult() 42 { 43 return 0 ; 44 } 45 int m_num1; 46 int m_num2; 47 }; 48 //加法计算器类 49 class addcalculatator : public abstractcalculator 50 { 51 public: 52 int getresult() 53 { 54 return m_num1 + m_num2; 55 } 56 }; 57 //减法计数器的类 58 class subcalculatator : public abstractcalculator 59 { 60 public: 61 int getresult() 62 { 63 return m_num1 - m_num2; 64 } 65 }; 66 //乘法计算器类 67 class mulcalculatator : public abstractcalculator 68 { 69 public: 70 int getresult() 71 { 72 return m_num1 * m_num2; 73 } 74 }; 75 //除法计算器类 76 class divicalculatator : public abstractcalculator 77 { 78 public: 79 int getresult() 80 { 81 return m_num1 / m_num2; 82 } 83 }; 84 void test02() 85 { 86 //多态使用条件 87 //父类指针或者引用指向子类对象 88 //加法运算 89 abstractcalculator* abc = new addcalculatator; 90 abc->m_num1 = 10; 91 abc->m_num2 = 10; 92 cout << abc->m_num1 << "+" << abc->m_num2 << "=" << abc->getresult() << endl; 93 //用完后记得销毁 94 delete abc; 95 //减法运算 96 abc = new subcalculatator; 97 abc->m_num1 = 10; 98 abc->m_num2 = 10; 99 cout << abc->m_num1 << "-" << abc->m_num2 << "=" << abc->getresult() << endl; 100 delete abc; 101 //乘法运算 102 abc = new mulcalculatator; 103 abc->m_num1 = 10; 104 abc->m_num2 = 10; 105 cout << abc->m_num1 << "*" << abc->m_num2 << "=" << abc->getresult() << endl; 106 delete abc; 107 //除法运算 108 abc = new divicalculatator; 109 abc->m_num1 = 10; 110 abc->m_num2 = 10; 111 cout << abc->m_num1 << "/" << abc->m_num2 << "=" << abc->getresult() << endl; 112 delete abc; 113 114 } 115 int main() 116 { 117 test02(); 118 }
总结:C++开发提倡利用多态设计程序架构,因为多态优点很多
纯虚函数和抽象类
1 #include <iostream> 2 using namespace std; 3 //纯虚函数和抽象类 4 class base 5 { 6 public: 7 //纯虚函数 8 //只要有一个纯虚函数,这个类称之为抽象类 9 //抽象类特点 10 //1.无法实例化对象 11 //2.抽象类的子类 必须重写父类中的纯虚函数,否则也属于抽象类 12 virtual void func() = 0; 13 }; 14 class son : public base 15 { 16 public: 17 virtual void func() 18 { 19 cout << "func 函数的调用" << endl; 20 } 21 }; 22 void test01() 23 { 24 // base b;//抽象类 无法实例化对象 25 // new base;//抽象类 无法实例化对象 26 //son s; //子类必须重写父类中的纯虚函数 否则无法实例化对象 27 base* ba = new son; 28 ba->func(); 29 } 30 int main() 31 { 32 test01(); 33 }
多态案例二-制作饮品
案例描述:
制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料
利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶
1 #include <iostream> 2 using namespace std; 3 class abcstractdrink 4 { 5 public: 6 //煮水 7 virtual void boil () = 0; 8 //冲泡 9 virtual void brew() = 0; 10 //倒入杯中 11 virtual void pourcup() = 0; 12 //加入辅料 13 virtual void putsomething() = 0; 14 //制作饮品 15 void makedrink() 16 { 17 boil(); 18 brew(); 19 pourcup(); 20 putsomething(); 21 } 22 }; 23 //制作咖啡 24 class coffe : public abcstractdrink 25 { 26 public: 27 //煮水 28 virtual void boil() 29 { 30 cout << "煮农夫山泉" << endl; 31 } 32 //冲泡 33 virtual void brew() 34 { 35 cout << "冲泡咖啡" << endl; 36 } 37 //倒入杯中 38 virtual void pourcup() 39 { 40 cout << "倒入杯中" << endl; 41 } 42 //加入辅料 43 virtual void putsomething() 44 { 45 cout << "加入糖和牛奶" << endl; 46 } 47 }; 48 //制作茶叶 49 class tea : public abcstractdrink 50 { 51 public: 52 //煮水 53 virtual void boil() 54 { 55 cout << "煮矿泉水" << endl; 56 } 57 //冲泡 58 virtual void brew() 59 { 60 cout << "冲泡茶叶" << endl; 61 } 62 //倒入杯中 63 virtual void pourcup() 64 { 65 cout << "倒入杯中" << endl; 66 } 67 //加入辅料 68 virtual void putsomething() 69 { 70 cout << "加入枸杞" << endl; 71 } 72 }; 73 //制作函数 74 void dowork(abcstractdrink* abs)//abcstractdrink* abs = new coffe 75 { 76 abs->makedrink(); 77 delete abs; 78 } 79 80 void test01() 81 { 82 //制作咖啡函数 83 dowork(new coffe);//abcstractdrink* abs = new coffe 84 cout << "-----------------------------" << endl; 85 //制作茶叶 86 dowork(new tea); 87 } 88 int main() 89 { 90 test01(); 91 }
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
1 class Animal { 2 public: 3 4 Animal() 5 { 6 cout << "Animal 构造函数调用!" << endl; 7 } 8 virtual void Speak() = 0; 9 10 //析构函数加上virtual关键字,变成虚析构函数 11 //virtual ~Animal() 12 //{ 13 // cout << "Animal虚析构函数调用!" << endl; 14 //} 15 16 17 virtual ~Animal() = 0; 18 }; 19 20 Animal::~Animal() 21 { 22 cout << "Animal 纯虚析构函数调用!" << endl; 23 } 24 25 //和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。 26 27 class Cat : public Animal { 28 public: 29 Cat(string name) 30 { 31 cout << "Cat构造函数调用!" << endl; 32 m_Name = new string(name); 33 } 34 virtual void Speak() 35 { 36 cout << *m_Name << "小猫在说话!" << endl; 37 } 38 ~Cat() 39 { 40 cout << "Cat析构函数调用!" << endl; 41 if (this->m_Name != NULL) { 42 delete m_Name; 43 m_Name = NULL; 44 } 45 } 46 47 public: 48 string *m_Name; 49 }; 50 51 void test01() 52 { 53 Animal *animal = new Cat("Tom"); 54 animal->Speak(); 55 56 //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏 57 //怎么解决?给基类增加一个虚析构函数 58 //虚析构函数就是用来解决通过父类指针释放子类对象 59 delete animal; 60 } 61 62 int main() { 63 64 test01(); 65 66 system("pause"); 67 68 return 0; 69 }
总结:
1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类
多态案例三-电脑组装
案例描述:
电脑主要组成部件为 CPU(用于计算),显卡(用于显示),内存条(用于存储)
将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商
创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
1 #include <iostream> 2 using namespace std; 3 class CPU 4 { 5 public: 6 virtual void calculate() = 0; 7 }; 8 class Videocard 9 { 10 public: 11 virtual void display() = 0; 12 }; 13 class Memory 14 { 15 public: 16 virtual void storage() = 0; 17 }; 18 class computer 19 { 20 public: 21 computer(CPU* cpu, Videocard* vc,Memory* mem) 22 { 23 m_cpu = cpu; 24 m_vc = vc; 25 m_mem = mem; 26 } 27 //提供工作的函数 28 void work() 29 { 30 //让零件工作起来,调用接口 31 m_cpu->calculate(); 32 m_vc->display(); 33 m_mem->storage(); 34 } 35 //提供析构函数,来释放三个电脑零件 36 ~computer() 37 { 38 if (m_cpu != 0) 39 { 40 delete m_cpu; 41 m_cpu = 0; 42 } 43 if (m_vc != 0) 44 { 45 delete m_vc; 46 m_vc = 0; 47 } 48 if (m_mem != 0) 49 { 50 delete m_mem; 51 m_mem = 0; 52 } 53 54 } 55 private: 56 CPU* m_cpu; 57 Videocard* m_vc; 58 Memory* m_mem; 59 }; 60 //具体厂商 61 class Intelcpu : public CPU 62 { 63 public: 64 void calculate() 65 { 66 cout << "intel 的cpu 开始工作了" << endl; 67 } 68 }; 69 class Intelvc : public Videocard 70 { 71 public: 72 void display() 73 { 74 cout << "intel 的videocard 开始工作了" << endl; 75 } 76 }; 77 class Intelmem : public Memory 78 { 79 public: 80 void storage() 81 { 82 cout << "intel 的memory 开始工作了" << endl; 83 } 84 }; 85 void test01() 86 { 87 CPU* intelcpu = new Intelcpu; 88 Videocard* intelvc = new Intelvc; 89 Memory* intelmem = new Intelmem; 90 computer *computer1=new computer(intelcpu, intelvc, intelmem); 91 computer1->work(); 92 delete computer1; 93 } 94 int main() 95 { 96 test01(); 97 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)