• c++(23)纯虚函数和抽象类、C语言函数指针的语法和意义


    1、纯虚函数和抽象类

    (1)、只要当类中拥有纯虚函数,无论这个类有没有成员变量,这个类都是一个抽象类,抽象类是不能够实例化的

    (2)、当一个普通的类,继承自抽象类的时候,一定要重写父类中的所有纯虚函数,否则这个类仍然是抽象类。

    (3)、被当做父类的抽象类,通常被当做API接口被提供,也常常使用抽象类的指针指向实例化的对象(父类指针指向子类对象)。

    下面是一个简单的纯虚函数构成抽象类的一个例子

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //人类
    6. class people
    7. {
    8. public:
    9. people(string name)
    10. {
    11. this->m_name = name;
    12. }
    13. virtual ~people()
    14. {
    15. }
    16. virtual void ActShow() = 0;//不同人群的行为模式不同
    17. protected:
    18. string m_name; //每个人都有姓名
    19. };
    20. //学生
    21. class student : public people
    22. {
    23. public:
    24. student(string name):people(name)
    25. {
    26. }
    27. void ActShow()
    28. {
    29. cout<<"student "<" 每天去学校学习"<
    30. }
    31. };
    32. //工人
    33. class workers : public people
    34. {
    35. public:
    36. workers(string name):people(name)
    37. {
    38. }
    39. void ActShow()
    40. {
    41. cout<<"workers "<" 每天去工地搬砖"<
    42. }
    43. };
    44. int main(void)
    45. {
    46. people *p1 = new student("zhang3");
    47. p1->ActShow();
    48. people *p2 = new workers("li4");
    49. p2->ActShow();
    50. return 0;
    51. }

    其中的people类就是一个抽象类,student类和worker类则是抽象类的一个具体实现,people类中的纯虚函数ActShow完全由子类来实现。

    这里就涉及到我们的一个,在c++多态程序设计的设计思路:向抽象层靠拢的程序设计思想

    业务层的代码程序设计,面向抽象类编程,降低代码耦合度。依赖倒转原则-----上层业务层和底层实现层,向中间抽象层靠拢。

    main函数就相当于是我们的一个业务需求,也就是业务层。当有很多业务的时候,也会封装成接口,按照逻辑顺序放到main中执行。业务层往往不关心,底层到底是怎么实现的,只关心抽象层。比如此例中,我们业务层只需要给我两个人群,一个是学生,一个是工人,并且打印出来他们的日常行为模式。

    抽象层就根据业务需求,提供一个人群类,在类中提供一个打印该人群日常行为模式的方法。抽象层也不关心底层怎么实现。

    底层实现层,也就是对应学生类和工人类的具体实现。

    2、C语言函数指针的语法和意义

    我们常说c语言是一门高级语言,c++的底层是C语言来实现的,那么接下来我们来讨论一下,C语言是如何实现c++的多态的。

    首先我们要知道学习C语言有两大块内容是绕不过去的,一个是指针,另一个是函数指针。

    先回顾一下三种函数指针的写法 

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //方式1
    6. typedef void (FUNC)(int, int);
    7. //方式2
    8. typedef void (*PFUNC)(int, int);
    9. void old_func(int a, int b)
    10. {
    11. cout<<"this is old_func..."<
    12. }
    13. int main(void)
    14. {
    15. FUNC *fp1 = NULL;
    16. fp1 = old_func;
    17. fp1(1, 2);
    18. PFUNC fp2 = NULL;
    19. fp2 = old_func;
    20. fp2(10, 20); //在调用的时候 不用考虑取*取&的问题,C语言编译器对这里优化了
    21. //方式3
    22. void (*fp3)(int, int) = NULL;
    23. fp3 = old_func;
    24. fp3(100, 200);
    25. return 0;
    26. }

    执行结果没有问题,打印了三次this is old_func...

    可以使用函数指针,来构成我们自己的C语言的抽象类。比如我们的抽象需求就是,完成f的一次功能调用,并给该实现传递两个参数。该功能可以是old_func,可以是其他的函数,只要满足形参列表是(int, int)且返回值是void,就可以。这样就像类似于c++中的纯虚函数

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //方式1
    6. typedef void (FUNC)(int, int);
    7. //方式2
    8. typedef void (*PFUNC)(int, int);
    9. void old_func(int a, int b)
    10. {
    11. cout<<"this is old_func..."<
    12. }
    13. void new_func(int a, int b)
    14. {
    15. printf("this is new_func...[a:%4d, b:%4d]\n", a, b);
    16. }
    17. //自定义的抽象框架,形参列表有三个,第一个是函数指针void(int,int),第2第3个参数就是int,int用来做函数指针的形参
    18. //函数指针可以使用三种方式中的任意一种
    19. int my_abstract_frame(PFUNC fp, int a, int b)
    20. {
    21. printf("my abstract frame...\n");
    22. fp(a, b);
    23. printf("do something else...\n -------------------\n");
    24. return 0;
    25. }
    26. int main(void)
    27. {
    28. #if 0
    29. //方式3
    30. void (*fp3)(int, int) = NULL;
    31. fp3 = old_func;
    32. fp3(100, 200);
    33. #endif
    34. my_abstract_frame(old_func, 666, 999);
    35. my_abstract_frame(new_func, 1000, 2000);
    36. return 0;
    37. }

    上面例子中的my_abstract_frame,就相当于是c++中的抽象类。我们在my_abstract_frame的定义中规定了传入的函数指针类型PFUNC。old_func和new_func,就相当于是子类的具体实现。当我们用不同的实现,做不同的事的时候,只要把对应类型的函数名传进去就可以了。

    这里也体现了一点C语言框架的思想。C程序工程业务框架的搭建者,只要定义好框架内做的事请,并规定好调用执行方法的类型,老程序员完成的旧业务old_func,新程序员不用关心old_func如何实现,只用关心自己的业务功能实现new_func,并满足方法的执行类型,塞到原有的框架里就可以了。c++中的抽象类实现,也许就是用的函数指针,这里不做深入的研究。

    这样也体现了,向抽象层靠拢的程序设计思想,业务层规定好框架,底层实现层完成具体功能。

  • 相关阅读:
    2022.9 PAT甲级题解
    基于SpringBoot的精准扶贫管理系统
    前端常用设计模式
    I/O软件层次
    C# Onnx Yolov8 Detect Poker 扑克牌识别
    js中的this举例介绍
    【C#版本】微信公众号模板消息对接(二)(图文详解)
    const用法精讲
    基于Matlab使用雷达资源管理有效跟踪多个机动目标仿真(附源码)
    Spark GC日志分析
  • 原文地址:https://blog.csdn.net/tr_ainiyangyang/article/details/125878938