C++_多态
2021/7/25 22:07:46
本文主要是介绍C++_多态,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
知识点1【多态的概述】(了解)
1、多态的分类:静态多态、动态多态
2、虚函数的引入
3、动态多态(重要)
4、虚函数的原理(了解)
知识点2【纯虚函数】(了解)
知识点3【重载、重定义(隐藏)、重写(覆盖)】(了解)
知识点4【多态案例】(了解)
知识点5【虚析构函数】(了解)
1、知识点的引入
2、虚析构(解决上述问题)
3、虚析构的原理(了解)
总结:虚函数和虚析构的区别?
虚函数:
虚析构:
知识点6【纯虚析构函数】(了解)
虚析构:
纯虚析构:
纯虚析构 函数和非纯析构函数不同点:
知识点1【多态的概述】(了解)
1、多态的分类:静态多态、动态多态
静态多态(静态联编、编译时多态):在编译的时候 就确定了函数的入口地址。(函数重载、运算符重载)
动态多态(动态联编、运行时多态):在运行的时候 就确定了函数的入口地址。(虚函数)
2、虚函数的引入
#include <iostream> using namespace std; class Animal { public: void speak(void) { cout<<"动物在唱歌"<<endl; } }; class Dog:public Animal { public: void speak(void) { cout<<"狗在汪汪"<<endl; } }; void test01() { //基类指针 指向 子类对象空间 Animal *p = new Dog; p->speak();//结果是动物在唱歌 } int main(int argc, char *argv[]) { test01(); return 0; } //动物在唱歌
3、动态多态(重要)
1、有继承
2、基类指针 指向 子类空间
3、基类的"同名"函数必须虚函数
4、子类重写(同名、同参、同返回值类型,不同函数功能)基类的虚函数。
这样 才能使用基类指针 操作 子类的"同名函数"
#include <iostream> using namespace std; class Animal { public: //虚函数 virtual void speak(void) { cout<<"动物在唱歌"<<endl; } }; class Dog:public Animal { public: //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"狗在汪汪"<<endl; } }; void test01() { //基类指针 指向 子类对象空间 Animal *p = new Dog; //必须要用基类指针 操作子类的同名函数 p->speak(); } int main(int argc, char *argv[]) { test01(); return 0; } //狗在汪汪
#include <iostream> using namespace std; class Animal { public: //虚函数 virtual void speak(void) { cout<<"动物在唱歌"<<endl; } }; class Dog:public Animal { public: //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"狗在汪汪"<<endl; } }; class Cat:public Animal { public: //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"猫在喵喵"<<endl; } }; class Mouse:public Animal { public: //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"老鼠在吱吱"<<endl; } }; void animalSpeak(Animal &ob) { ob.speak(); } void test02() { Dog dog; Cat cat; Mouse mouse; animalSpeak(dog); animalSpeak(cat); animalSpeak(mouse); } int main(int argc, char *argv[]) { test02(); return 0; } //狗在汪汪 //猫在喵喵 //老鼠在吱吱
4、虚函数的原理(了解)
1、分析Animal类
class Animal { public: //虚函数 virtual void speak(void) { cout<<"动物在唱歌"<<endl; } };
当拥有虚函数的基类 不涉及到继承时,会产生一个vfptr(virtual function ptr)虚函数指针,该虚函数指针指向了一张虚函数表(vftable), vftable保存基类的同名函数入口地址。
2、分析Dog类:
当涉及到继承时:基类的虚函数指针、虚函数表 都会被继承到子类中,如果子类重写 基类的虚函数。会将虚函数表中的入口地址 更改成 子类的“同名”函数。所以这时使用基类指针调用的函数 是子类的同名函数。
拓展:
知识点2【纯虚函数】(了解)
在基类中 不实现虚函数的函数体。这样的虚函数 叫纯虚函数。
class Animal { public: //纯虚函数 =0 不实现函数体 virtual void speak(void)=0; };
如果一个类中 只要有一个纯虚函数 那么这个类 是抽象类。
抽象类 不能实例化对象。
Animal ob;//err 抽象类 不能实例化对象
抽象基类 派生出子类 ,子类必须重写基类的所有纯虚函数。否则子类 也是抽象类。
#include <iostream> using namespace std; class Animal { public: //纯虚函数 =0 不实现函数体 virtual void speak(void)=0; }; class Dog:public Animal { public: //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"狗在汪汪"<<endl; } }; void test01() { //Animal ob;//err 抽象类不能实例化对象 //基类指针 指向 子类对象空间 Animal *p = new Dog; //必须要用基类指针 操作子类的同名函数 p->speak(); } int main(int argc, char *argv[]) { test01(); return 0; }
知识点3【重载、重定义(隐藏)、重写(覆盖)】(了解)
重载:没有继承、函数重载、运算符重载(静态多态)
重定义:必须有继承,子类重定义父类的非虚函数(参数类型、个数、顺序,函数的返回值类型都可以不同)。(静态多态)
重写:必须有继承,子类重写父类的虚函数(参数类型、个数、顺序,返回值类型 必须一致)(动态多态)
知识点4【多态案例】(了解)
#include <iostream> using namespace std; //抽象制作饮品 class AbstractDrinking{ public: //烧水 virtual void Boil() = 0; //冲泡 virtual void Brew() = 0; //倒入杯中 virtual void PourInCup() = 0; //加入辅料 virtual void PutSomething() = 0; //规定流程 void MakeDrink(){ this->Boil(); Brew(); PourInCup(); PutSomething(); } }; class Coffee : public AbstractDrinking{ public: //烧水 virtual void Boil(){ cout << "煮农夫山泉!" << endl; } //冲泡 virtual void Brew(){ cout << "冲泡咖啡!" << endl; } //倒入杯中 virtual void PourInCup(){ cout << "将咖啡倒入杯中!" << endl; } //加入辅料 virtual void PutSomething(){ cout << "加入牛奶!" << endl; } }; //制作茶水 class Tea : public AbstractDrinking{ public: //烧水 virtual void Boil(){ cout << "煮自来水!" << endl; } //冲泡 virtual void Brew(){ cout << "冲泡茶叶!" << endl; } //倒入杯中 virtual void PourInCup(){ cout << "将茶水倒入杯中!" << endl; } //加入辅料 virtual void PutSomething(){ cout << "加入食盐!" << endl; } }; //业务函数 void DoBussiness(AbstractDrinking* drink){ drink->MakeDrink(); delete drink; } void test(){ DoBussiness(new Coffee); cout << "--------------" << endl; DoBussiness(new Tea); } int main(int argc, char *argv[]) { test(); return 0; }
知识点5【虚析构函数】(了解)
1、知识点的引入
#include <iostream> using namespace std; class Animal { public: Animal() { cout<<"Animal的无参构造"<<endl; } //纯虚函数 =0 不实现函数体 virtual void speak(void)=0; ~Animal() { cout<<"Animal析构函数"<<endl; } }; class Dog:public Animal { public: Dog() { cout<<"Dog的无参构造"<<endl; } //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"狗在汪汪"<<endl; } ~Dog() { cout<<"Dog的析构函数"<<endl; } }; void test01() { //Animal ob;//err 抽象类不能实例化对象 //基类指针 指向 子类对象空间 Animal *p = new Dog; //必须要用基类指针 操作子类的同名函数 p->speak(); delete p; } int main(int argc, char *argv[]) { test01(); return 0; }
2、虚析构(解决上述问题)
#include <iostream> using namespace std; class Animal { public: Animal() { cout<<"Animal的无参构造"<<endl; } //纯虚函数 =0 不实现函数体 virtual void speak(void)=0; virtual ~Animal() { cout<<"Animal析构函数"<<endl; } }; class Dog:public Animal { public: Dog() { cout<<"Dog的无参构造"<<endl; } //子类的同名、同参、同返回值类型的函数 默认也是virtual (子类的virtual可以省略) virtual void speak(void) { cout<<"狗在汪汪"<<endl; } ~Dog() { cout<<"Dog的析构函数"<<endl; } }; void test01() { //Animal ob;//err 抽象类不能实例化对象 //基类指针 指向 子类对象空间 Animal *p = new Dog; //必须要用基类指针 操作子类的同名函数 p->speak(); delete p; } int main(int argc, char *argv[]) { test01(); return 0; }
3、虚析构的原理(了解)
Animal的类的布局:
Dog的类的布局
总结:虚函数和虚析构的区别?
虚函数:
虚函数一般指的是虚成员函数,成员函数名前加virtual修饰,需要实现函数体,子类必须重写 父类的虚函数(函数的参数个数、顺序、类型,返回值类型必须完全一直)。 用户可以使用父类指针 操作 子类重写的虚函数。
虚析构:
父类的析构函数名前加virtual修饰,需要实现函数体,子类只需实现子类的析够函数即可,用户使用delete释放 父类指针 达到释放整个子类空间的效果。
知识点6【纯虚析构函数】(了解)
虚析构:
class Base { public: virtual ~Base() { //函数体 } }
纯虚析构:
class Base//抽象类 { public: virtual ~Base()=0 { //必须有函数体 } }
纯虚析构 函数和非纯析构函数不同点:
纯虚析构函数使得基类是抽象类,不能创建基类的对象。
这篇关于C++_多态的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22怎么通过控制台去看我的页面渲染的内容在哪个文件中呢-icode9专业技术文章分享
- 2024-12-22el-tabs 组件只被引用了一次,但有时会渲染两次是什么原因?-icode9专业技术文章分享
- 2024-12-22wordpress有哪些好的安全插件?-icode9专业技术文章分享
- 2024-12-22wordpress如何查看系统有哪些cron任务?-icode9专业技术文章分享
- 2024-12-21Svg Sprite Icon教程:轻松入门与应用指南
- 2024-12-20Excel数据导出实战:新手必学的简单教程
- 2024-12-20RBAC的权限实战:新手入门教程
- 2024-12-20Svg Sprite Icon实战:从入门到上手的全面指南
- 2024-12-20LCD1602显示模块详解
- 2024-12-20利用Gemini构建处理各种PDF文档的Document AI管道