• C++:多态与虚函数,纯虚函数


    1.多态的机制与虚函数的机制

    1.1 多态的机制


    1.当在类中使用virtual声明一个函数为虚函数时,在编译时,编译器会自动在基类中默默地安插一个虚函数表指针,同时的.rodata段为这类生成一张虚函数表,用来保存类中的虚函数的地址。

    2.当继承发生时,父类中的虚指针就被子类给继承了下来,所以他的类对象空间就增大了一个指针的大小。

    3.当子类构造对象时,这根继承而来的虚指针,将会在子类的构造函数中被重新赋值,所赋的值即为子类类中产生的虚函数表地址。

    4.当使用父类指针或引用,对虚函数进行调用时,通过这个虚函数表指针,在虚函数表中查找虚函数的地址,从而调用不同类的虚函数。

    1.2 虚函数的机制

    虚函数的意义何在?就是用来承接动态多态的。他是如何承接这种动态多态机制的呢?

    当子类之中函数与父类之中的虚函数重名时,且返回值与形参列表都一致时,将是对父类虚函数的重写。当在子类重写虚函数时,将会把虚函数表中的父类的虚函数地址覆盖掉。

    注释:虚函数的具体可以去看主页文章,单继承与多进程

    1.3虚函数表的结构图

     

    1.4 动态多态实现的三个前提件(很重要)

    1.有继承关系
    2.基类中有虚函数,且子类重写虚函数
    3.基类指针或引用,指向或引用父类对象,就会形成动态多态

    2.多态实例应用

    1. #include
    2. using namespace std;
    3. class Driver{
    4. public:
    5. virtual void show_info()
    6. {
    7. cout<<"我是司机"<
    8. }
    9. };
    10. class Bwm:public Driver
    11. {
    12. public:
    13. void show_info()
    14. {
    15. cout<<"我开的是宝马"<
    16. }
    17. };
    18. class Benchi:public Driver
    19. {
    20. public:
    21. void show_info()
    22. {
    23. cout<<"我开的是奔驰"<
    24. }
    25. };
    26. class Tuolaji:public Driver
    27. {
    28. public:
    29. void show_info()
    30. {
    31. cout<<"我开的是拖拉机"<
    32. }
    33. };
    34. class Kai
    35. {
    36. public:
    37. void kaiche(Driver& p)
    38. {
    39. p.show_info();
    40. }
    41. };
    42. int main()
    43. {
    44. Bwm bwm;
    45. Tuolaji tuolaji;
    46. Benchi benchi;
    47. Kai p;
    48. p.kaiche(tuolaji);
    49. p.kaiche(benchi);
    50. p.kaiche(benchi);
    51. return 0;
    52. }

    结果图:

    3.多态的巨大问题与虚析构

    3.1代码举例说明

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A()
    7. {
    8. cout<<"A的构造"<
    9. }
    10. ~A()
    11. {
    12. cout<<"A的析构"<
    13. }
    14. virtual void show_info()
    15. {
    16. cout<<"爱吃饭"<
    17. }
    18. };
    19. class B:public A
    20. {
    21. public:
    22. B()
    23. {
    24. cout<<"B的构造"<
    25. }
    26. ~B()
    27. {
    28. cout<<"B的析构"<
    29. }
    30. void show_info()
    31. {
    32. cout<<"爱吃糖"<
    33. }
    34. };
    35. int main()
    36. {
    37. A* a=new B;
    38. a->show_info();
    39. delete a;
    40. return 0;
    41. }

    结果图:

     由图可知:当用虚函数实现多态的时候,子类的的析构无法进行。

    所以我们应该怎么解决呢?

    3.2代码实现

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A()
    7. {
    8. cout<<"A的构造"<
    9. }
    10. virtual~A()
    11. {
    12. cout<<"A的析构"<
    13. }
    14. virtual void show_info()
    15. {
    16. cout<<"爱吃饭"<
    17. }
    18. };
    19. class B:public A
    20. {
    21. public:
    22. B()
    23. {
    24. cout<<"B的构造"<
    25. }
    26. ~B()
    27. {
    28. cout<<"B的析构"<
    29. }
    30. void show_info()
    31. {
    32. cout<<"爱吃糖"<
    33. }
    34. };
    35. int main()
    36. {
    37. A* a=new B;
    38. a->show_info();
    39. delete a;
    40. return 0;
    41. }

    结果图:

     

    所以,为了避免子类的析构无法执行而造成的内存泄漏问题,应该把最远端父类的析构函数定义为虚析构。虚析构的语法即是在最远端父类的析构函数名前 加virtual进行修饰即可。

     虚析构如下:

    1. virtual~A()
    2. {
    3. //虚析构的定义形式。
    4. }

     

    4.纯虚函数与抽象类

    4.1纯虚函数语法格式:

    1. class + 类名
    2. {
    3. public:
    4. virtual void showInfo() = 0;
    5. };

    4.2纯虚函数的定义

    在类中定义一个没有函数体的虚函数就叫做纯虚函数。类中有纯虚函数的类就叫做抽象类。抽象类被人称接口类。这个纯虚函数只有一个函数名做为函数功能的表现,而没有函数体的实现。纯虚函数必须在子类之中进行实现,如果继承的子类没有实现父类的纯虚函数,那么这个子类也将成员抽象类。抽象类是不可以定义对象的。纯虚函数也叫接口类中的接口。

    4.3抽象类的应用实例

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. virtual void show_info()=0;
    7. virtual void goshopping()=0;
    8. };
    9. class B:public A
    10. {
    11. public:
    12. void show_info()
    13. {
    14. cout<<"我是大哥"<
    15. }
    16. void goshopping()
    17. {
    18. cout<<"我是小弟"<
    19. }
    20. };
    21. int main()
    22. {
    23. A* a=new B;
    24. a->show_info();
    25. a->goshopping();
    26. return 0;
    27. }

  • 相关阅读:
    Python笔记——linux/ubuntu下安装mamba,安装bob.learn库
    94-98-Hadoop-MapReduce工作流程(重要)
    nginx实现灰度上线(InsCode AI 创作助手)
    好用的跨平台同步笔记工具,手机和电脑可同步的笔记工具
    Web开发:<p>标签作用
    JavaSE——异常
    使用Python进行机器学习:从基础到实战
    Maven核心概念全解析
    【STM32 定时器(二)TIM 输入捕获PWM 总结】
    Android项目集成穿山甲开屏/插屏/横幅广告教程大全
  • 原文地址:https://blog.csdn.net/a2998658795/article/details/126039682