c 工程 1.3 c 程序生命周期和回调函数-凯发app官方网站

凯发app官方网站-凯发k8官网下载客户端中心 | | 凯发app官方网站-凯发k8官网下载客户端中心
  • 博客访问: 1235458
  • 博文数量: 76
  • 博客积分: 1959
  • 博客等级: 上尉
  • 技术积分: 2689
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-19 12:07
个人简介

樽中酒不空

文章分类

全部博文(76)

文章存档

2020年(4)

2019年(1)

2017年(2)

2016年(2)

2015年(7)

2014年(11)

2013年(13)

2012年(18)

2011年(2)

2010年(16)

相关博文
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·

分类: c/c

2020-08-11 13:59:46

一 生命周期

可以把程序看成一个生命体,也有出生、成长、结束的阶段,每个阶段都可能会有让外界来参与的需求(比如人生病了需要外界治疗,自身抵抗力不能完全自愈),如果有windows开发经验,很容易想起wm_create, wm_destory等消息。 或者移动端(安卓、ios)的程序起止事件响应,甚至页面切换的事件。在每个事件中,提供了一个中断(回调函数),可以和外界进行交互。最简单的例子就是程序启动时增加一个启动画面,很多软件在退出的时候弹出一个提示窗口或打开一个浏览器链接(这种做法非常不友好,不推荐)。需要在程序的相应位置提供一个可以由外面参与的机会。这时回调函数就派上用场了。

二 回调函数一般是使用c语言的方法,不过,c 因为自身的特点,可以使用更恰当的办法(不存在好坏),我们这里使用抽象基类做参数的方法来实现,这是一种很传统的方法了,比如com本质论这本书上第一章就讲解过。
(本文涉及到虚函数的一些知识,还有抽象基类,一般c 教材会讲到。)

本文在前文的代码上面增加回调机制。

以下先讲关键代码。

点击(此处)折叠或打开

  1. #include <iostream>// stl cout
  2. #include <signal.h>//signal头文件
  3. #include <chrono> //stl chrono头文件,时间工具,可以精确到,可以精确到纳秒
  4. #include <thread> //stl thread

  5. #include "include/glog/logging.h"
  6. #pragma comment(lib, "lib/release/glog.lib")
  7. using namespace google;

  8. class iappcb
  9. {
  10. public:
  11.     virtual int oninit() = 0;
  12.     virtual int ondestroy() = 0;
  13. };

  14. class appcbimpl :public iappcb
  15. {
  16. public:
  17.     virtual int oninit()
  18.     {
  19.         std::cout << "oninit\n";
  20.         
  21.         return 0;
  22.     };
  23.     virtual int ondestroy()
  24.     {
  25.         std::cout << "ondestroy\n";
  26.         return 0;
  27.     };
  28. };


  29. static int signaled = 0;
  30. static void sigterm_handler(int sig)
  31. {
  32.     signaled = 1;
  33. }

  34. class app
  35. {
  36. public:
  37.     void run()
  38.     {
  39.         //std::chrono::milliseconds可以是以下四个中的一个:seconds,milliseconds,microseconds,nanoseconds
  40.         uint64_t start_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>
  41.             (std::chrono::system_clock::now().time_since_epoch()).count();
  42.         for (;;)
  43.         {
  44.             if (signaled == 1)
  45.                 break;
  46.             else
  47.             {
  48.                 std::cout << "运行毫秒数:" << std::chrono::duration_cast<std::chrono::milliseconds>
  49.                     (std::chrono::system_clock::now().time_since_epoch()).count() - start_millseconds << std::endl;

  50.                 //c11支持u8转utf8,否则写到文件里乱码
  51.                 log(info) << u8"运行毫秒数:" << std::chrono::duration_cast<std::chrono::milliseconds>
  52.                     (std::chrono::system_clock::now().time_since_epoch()).count() - start_millseconds ;
  53.                 std::this_thread::sleep_for(std::chrono::seconds(1));
  54.             }
  55.         }
  56.     };
  57. };

  58. iappcb* m_pcb = nullptr;
  59. int main()
  60. {
  61.     m_pcb = new appcbimpl;
  62.     google::initgooglelogging("demo3.exe");//
  63.     google::setlogdestination(google::glog_info, "demo3_");
  64.     log(info) << "hello world!";
  65.     std::cout << "hello world!\n";
  66.     if (m_pcb->oninit() != 0)//程序启动时由外部确定需要执行哪些操作,比如显示欢迎页。如果程序初始化失败,oninit 非0数值,程序退出。
  67.     {
  68.         delete m_pcb;
  69.         m_pcb = nullptr;
  70.         return 0;
  71.     }
  72.     signal(sigint, sigterm_handler); //ctrl c中断


  73.     app app;
  74.     app.run();
  75.     std::cout << "exit!\n";
  76.     log(info) << "exit!";
  77.     m_pcb->ondestroy();//程序退出前由外部决定还要执行哪些操作,比如各种流氓软件退出时弹出页面。

  78.     std::this_thread::sleep_for(std::chrono::seconds(1));
  79.     google::shutdowngooglelogging();
  80.     
  81.     delete m_pcb;
  82.     m_pcb = nullptr;
  83.     return 0;
  84. }

这个代码主要是在前文的基础上增加了两个class,一个是抽象基类:iappcb,这个名字的意思是 app的回调函数接口。一般class名字第一个字母用i 表示是接口(intereface),写过com的朋友很清楚。最后两个字母cb表示回调(callback),使用过微软sdk的朋友也有感觉,比如directshow里面大量的cb类。

appcbimpl继承iappcb,名字带impl,如果了解设计模式会知道这是其中桥接模式(bridge),写java代码中会经常使用。
这两个类,iappcb声明接口,appcbimpl负责实现,标准的面象对象设计方法。因为c 首先是兼容c,所以一般初学都没有这方面意识,大多还是面向过程的方式来写代码。而java是重新设计的,最初就采用了这种模式,可能好多人还不了解什么是设计模式,就照葫芦画瓢模仿着写,所以感觉java学起来比c 容易。其实只要理解了里面的知识点,用哪种语言写起来都一样。

继续来,iappcb* m_pcb = nullptr;
然后再代码里m_pcb = new appcbimpl;
这样写还是面向过程,不是完全的面向对象。不过还不急,这部分还相当于伪代码,演示作用,后续会慢慢纠正。

本文重点是增加了两处:
第一处:if (m_pcb->oninit() != 0)
代码的注释里也写了,这相当于一般程序的启动时,通知外界,是否需要干涉。一般可以在这个函数里做一些初始化的动作。
第二处:
m_pcb->ondestroy();
这是程序退出时要执行的操作。比如一般程序在退出时保存当前执行状态,关键的参数等。

回调函数除了程序本身用以外,还可以对外开放。比如程序本身封成sdk,源码不可能,但提供 还 iappcb的接口,调用着可以自己定义一个子类执行具体参数,然后把接口声音的变量传到主程序中,可以自己控制程序的执行。

本文完整代码在
与文中的一致。



阅读(1906) | 评论(0) | 转发(0) |
0

上一篇:c 工程 1.2 使用glog写日志

下一篇:没有了

给主人留下些什么吧!~~
")); function link(t){ var href= $(t).attr('href'); href ="?url=" encodeuricomponent(location.href); $(t).attr('href',href); //setcookie("returnouturl", location.href, 60, "/"); }
网站地图