【C++之剑】我不允许你还不会多态

[复制链接]
发表于 2026-2-12 00:18:39 | 显示全部楼层 |阅读模式

2024年7月15日



 学习编程就得循环渐进,踏实根本,勿在浮沙筑高台  

 循环渐进Forward-CSDN博客


Hello,这里是kiki,本日继续更新C++部分,我们继续来扩充我们的知识面,我盼望能积极把抽象繁多的知识讲的生动又普通易懂,本日要讲的是C++三大特性的多态~

目次
 循环渐进Forward-CSDN博客

多态的概念
多态的界说及实现
多态的构成条件
虚函数
虚函数的重写
虚函数重写的两个破例:
C++11 override 和 final
重载、覆盖(重写)、潜伏(重界说)的对比
抽象类
接口继续和实现继续
多态的原理
虚函数表
多态的原理
动态绑定与静态绑定
单继续和多继续关系中的虚函数表


多态的概念

             多态的概念:普通来说,就是多种形态,具体点就是去完成某个举动,当差异的对象去完成时会 产生出差异的状态 。   举个栗子:比如买票这个举动 ,当 平常人 买票时,是全价买票; 门生 买票时,是半价买票; 武士买票时是优先买票。      再举个栗子:   迩来为了  争取在线付出市场  ,付出宝年底经常会做诱人的  扫红包  -  付出  -  给嘉奖金  的 活动。那么各人想想为什么有人扫的红包又大又奇怪8  块、  10  块  ...  ,而有人扫的红包都是  1  毛,  5 毛....  。实在这背后也是一个多态举动。付出宝起首会分析你的账户数据,比如你是新用户、比如你没有经常付出宝付出等等,那么你必要被鼓励利用付出宝,那么就你扫码金额 =random()%99;比如你经常利用付出宝付出大概付出宝账户中常年没钱,那么就不必要太鼓励你去利用付出宝,那么就你扫码金额 = random()%1  ;总结一下:  同样是扫码动作,差异的用户扫  得到的不一样的红包,这也是一种多态举动。  ps  :付出宝红包标题纯属瞎编,各人仅供娱乐。      
  
    多态的界说及实现


多态的构成条件

          多态是在差异继续关系的类对象,去调用同一函数,产生了差异的举动。比如Student 继续了   Person 。 Person 对象买票全价, Student对象买票半价。        
那么在继续中要构成多态尚有两个条件
          1. 必须通过基类的指针大概引用 调用虚函数           2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数举行 重写


虚函数

     虚函数:即被  virtual  修饰的类成员函数称为虚函数。   
  1. class Person {
  2. public:
  3.         virtual void BuyTicket() { cout << "买票-全价" << endl; }
  4. };
复制代码

虚函数的重写

           虚函数的重写(覆盖):派生类中有一个跟基类完全类似的虚函数(即派生类虚函数与基类虚函数的返回值范例、函数名字、参数列表完全类似),称子类的虚函数重写了基类的虚函数。
   
  1. class Person {
  2. public:
  3.         virtual void BuyTicket() { cout << "买票-全价" << endl; }
  4. };class Student : public Person {public:        virtual void BuyTicket() { cout << "买票-半价" << endl; }};
复制代码

虚函数重写的两个破例:

  1.  协变 ( 基类与派生类虚函数返回值范例差异 )      派生类重写基类虚函数时,与基类虚函数返回值范例差异。即基类虚函数返回基类对象的指      针大概引用,派生类虚函数返回派生类对象的指针大概引用时,称为协变。(相识)   
  1. class A {};
  2. class B : public A {};
  3. class Person {
  4. public:
  5.         virtual A* f() { return new A; }
  6. };
  7. class Student : public Person {
  8. public:
  9.         virtual B* f() { return new B; }
  10. };
复制代码
2. 析构函数的重写(基类与派生类析构函数的名字差异)
     如果基类的析构函数为虚函数,此时派生类析构函数只要界说,无论是否加  virtual  关键字,      都与基类的析构函数构成重写,固然基类与派生类析构函数名字差异。固然函数名不类似,      看起来违反了重写的规则,实在否则,这里可以明白为编译器对析构函数的名称做了特殊处      理,编译后析构函数的名称同一处置处罚成  destructor  。     
  1. class Person {
  2. public:
  3.         virtual ~Person() { cout << "~Person()" << endl; }
  4. };
  5. class Student : public Person {
  6. public:
  7.         virtual ~Student() { cout << "~Student()" << endl; }
  8. };
  9. // 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
  10. 数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
  11. int main()
  12. {
  13.         Person* p1 = new Person;
  14.         Person* p2 = new Student;
  15.         delete p1;
  16.         delete p2;
  17.         return 0;
  18. }
复制代码

C++11 override final

     C++11  提供了  override  和  final  两个关键字,可以帮 助用户检测是否重写。    1. final:修饰虚函数,表现该虚函数不能再被重写
  
  1. class Car
  2. {
  3. public:
  4. virtual void Drive() final {}
  5. };
  6. class Benz :public Car
  7. {
  8. public:
  9. virtual void Drive() {cout << "Benz-舒适" << endl;}
  10. };
复制代码

2.  override: 查抄派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。     
  1. class Car{
  2. public:
  3. virtual void Drive(){}
  4. };
  5. class Benz :public Car {
  6. public:
  7. virtual void Drive() override {cout << "Benz-舒适" << endl;}
  8. };
复制代码
   
重载、覆盖(重写)、潜伏(重界说)的对比

  





抽象类

     在虚函数的反面写上   =0   ,则这个函数为纯虚函数。  包罗纯虚函数的类叫做抽象类(也叫接口  类),抽象类不能实例化出对象  。派生类继续后也不能实例化出对象,只有重写纯虚函数,派生类才华实例化出对象。纯虚函数规范了派生类必须重写,别的纯虚函数更表现出了接口继续。     
  1. class Car
  2. {
  3. public:
  4. virtual void Drive() = 0;
  5. };
  6. class Benz :public Car
  7. {
  8. public:
  9. virtual void Drive()
  10. {
  11. cout << "Benz-舒适" << endl;
  12. }
  13. };
  14. class BMW :public Car
  15. {
  16. public:
  17. virtual void Drive()
  18. {
  19. cout << "BMW-操控" << endl;
  20. }
  21. };
  22. void Test()
  23. {
  24. Car* pBenz = new Benz;
  25. pBenz->Drive();
  26. Car* pBMW = new BMW;
  27. pBMW->Drive();
  28. }
复制代码
接口继续和实现继续

   
    平常函数的继续是一种实现继续,派生类继续了基类函数,可以利用函数,继续的是函数的实现。虚函数的继续是一种接口继续,派生类继续的是基类虚函数的接口,目标是为了重写,告竣多态,继续的是接口。以是如果不实现多态,不要把函数界说成虚函数。   
多态的原理

虚函数表

     一个含有虚函数的类中都至少都有一个虚函数表指针,由于虚函数的所在要被放到虚函数表中,虚函数表也简称虚表   
多态的原理




     1.   观察下图的赤色箭头我们看到,  p  是指向  mike  对象时,  p->BuyTicket  在  mike  的虚表中找到虚函数是Person::BuyTicket  。      2.   观察下图的蓝色箭头我们看到,  p  是指向  johnson  对象时,  p->BuyTicket  在  johson  的虚表中      找到虚函数是  Student::BuyTicket  。      3.   如许就实现出了差异对象去完成同一举动时,显现出差异的形态。      4.   反过来思索我们要到达多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用虚函数。反思一下为什么?      5.   再通过下面的汇编代码分析,  看出满意多态以后的函数调用,不是在编译时确定的,是运行  起来以后到对象的中取找的。不满意多态的函数调用时编译时确认好的  。   

动态绑定与静态绑定

     1.   静态绑定又称为前期绑定  (  早绑定  )  ,  在步调编译期间确定了步调的举动  ,  也称为静态多态  , 比如:函数重载      2.   动态绑定又称后期绑定  (  晚绑定  )  ,是在步调运行期间,根据具体拿到的范例确定步调的具体举动,调用具体的函数,也称为动态多态  。   
单继续和多继续关系中的虚函数表

   
    必要注意的是在单继续和多继续关系中,下面我们去关注的是派生类对象的虚表模子,由于基类的虚表模子前面我们已经看过了,没什么必要特殊研究的   
学习编程就得循环渐进,踏实根本,勿在浮沙筑高台 




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表