• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2020-04-28 16:10 Aet 隐藏边栏 |   抢沙发  8 
文章评分 1 次,平均分 5.0

STL

STL容器

  1. 顺序容器
    1. string
    2. vector
    3. list
    4. forward_list
    5. queue
    6. deque
    7. stack
  2. 关联容器
    1. map
    2. set
    3. unordered_map
    4. unordered_set

STL容器底层数据结构

  1. vector
    1. 顺序表
    2. 维护的是一个连续线性空间,是物理上的连续
  2. list
    1. 双向链表,是逻辑上的连续
  3. forward_list
    • 单链表封装,是逻辑上的连续
  4. deque
    1. 多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪
  5. stack
    1. 默认双端队列实现(deque)
    2. 运算受限的线性表
  6. queue
    1. 运算受限的线性表(deque)
  7. priority_queue
    1. 默认vector实现
    2. 顺序表
  8. array
    1. std风格的数组
  9. map/set
    1. 红黑树
  10. unordered_map/unordered_set
    1. 哈希表

      Windows消息处理机制

概述

Windows 是事件驱动的,事件驱动围绕着消息的产生与处理展开,事件驱动是靠消息循环机制来实现的。也可以理解为消息是一种报告有关事件发生的通知。

消息(Message)指的就是Windows 操作系统发给应用程序的一个通告,它告诉应用程序某个特定的事件发生了。

比如,用户单击鼠标或按键都会引发Windows 系统发送相应的消息。最终处理消息的是应用程序的窗口函数,如果程序不负责处理的话系统将会作出默认处理。

从数据结构的角度来说,消息是一个结构体,它包含了消息的类型标识符以及其他的一些附加信息。

系统定义的结构体MSG用于表示消息,MSG 具有如下定义形式:

Windows 是一消息(Message)驱动式系统,Windows 消息提供了应用程序与应用程序
之间、应用程序与Windows 系统之间进行通讯的手段。

应用程序要实现的功能由消息来触发,并靠对消息的响应和处理来完成。

所谓消息就是描述事件发生的信息,Windows 程序是事件驱动的,用这一方法编写程序避免了死板的操作模式,因为Windows 程序的执行顺序将取决于事件的发生顺序,具有不可预知性。

消息队列

Windows 系统中有两种消息队列

  • 一种是系统消息队列
  • 另一种是应用程序消息队列

计算机的所有输入设备由 Windows 监控,当一个事件发生时,Windows 先将输入的消息放入系统消息队列中,然后再将输入的消息拷贝到相应的应用程序队列中,应用程序中的消息循环从它的消息队列中检索每一个消息并发送给相应的窗口函数中。

Windows 操作系统为每个线程维持一个消息队列,当事件产生时,操作系统感知这一事件的发生,并包装成消息发送到消息队列,应用程序通过GetMessage()函数取得消息并存于一个消息结构体中,然后通过一个TranslateMessage()DispatchMessage()解释和分发消息

TranslateMessage(&msg)对于大多数消息而言不起作用,但是有些消息,比如键盘按键按下和弹起(分别对于KeyDownKeyUp 消息),却需要通过它解释,产生一个WM_CHAR消息。DispatchMessage(&msg)负责把消息分发到消息结构体中对应的窗口,交由窗口过程函数处理。GetMessage()在取得WM_QUIT 之前的返回值都为TRUE,也就是说只有获取到WM_QUIT 消息才返回FALSE,才能跳出消息循环。

消息循环

消息循环是Windows 应用程序存在的根本,应用程序通过消息循环获取各种消息,并通过相应的窗口过程函数,对消息加以处理。

正是这个消息循环使得一个应用程序能够响应外部的各种事件,所以消息循环往往是一个Windows 应用程序的核心部分。

消息处理

取得的消息将交由窗口处理函数进行处理,对于每个窗口类Windows为我们预备了一个默认的窗口过程处理函数DefWindowProc(),这样做的好处是,我们可以着眼于我们感兴趣的消息,把其他不感兴趣的消息传递给默认窗口过程函数进行处理。

每一个窗口类都有一个窗口过程函数,此函数是一个回调函数,它是由Windows操作系统负责调用的,而应用程序本身不能调用它。以switch语句开始,对于每条感兴趣的消息都以一个case引出。

对于每条已经处理过的消息都必须返回0,否则消息将不停的重试下去;对于不感兴趣的消息,交给DefWindowProc()函数进行处理,并需要返回其处理值。

MFC消息映射

在MFC 的框架结构下,“消息映射”是通过巧妙的宏定义,形成一张消息映射表格来进行的。

这样一旦消息发生,Framework 就可以根据消息映射表格来进行消息映射和命令传递。

  • 首先在需要进行消息处理的类的头文件(.H)里,都会含有DECLARE_MESSAGE_MAP()宏, 声明该类拥有消息映射表格。
  • 然后在类应用程序文件(.CPP)实现这一表格

  • BEGIN_MESSAGE_MAP
    • 参数1:拥有消息表格的类
    • 参数2:拥有消息表格的类的父类
  • ON_COMMAND
    • 指定命令,消息的处理函数
  • END_MESSAGE_MAP()
    • 结尾符号
  • DECLARE_MESSAGE_MAP
    • AFX_MSGMAP_ENTRY
      • 包含了一个消息的所有相关信息
    • AFX_MSGMAP
      • 用来得到基类的消息映射入口地址
      • 得到本身的消息映射入口地址

实际上,MFC 把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。

同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址。

当本身对该消息不响应的时候,就可以上溯到基类的消息映射表寻找对应的消息响应。

MFC 通过钩子函数_AfxCbtFilterHook()截获消息,并在此函数中把窗口过程函数设置为AfxWindProc,而原来的窗口过程函数被保存在成员变量m_pfnSuper中。

MFC消息映射的步骤

  • 函数AfxWndProc接收Windows操作系统发送的消息。
  • 函数AfxWndProc调用函数AfxCallWndProc进行消息处理,这里一个进步是把对句柄的操作转换成对CWnd 对象的操作。
  • 函数AfxCallWndProc调用CWnd 类的方法WindowProc进行消息处理
  • WindowProc 调用OnWndMsg进行正式的消息处理,即把消息派送到相关的方法中去处理
  • 如果OnWndMsg方法没有对消息进行处理的话,就调用DefWindowProc对消息进行处理

MFC消息分类

  • 命令消息(WM_COMMAND)
    • 比如菜单项的选择,工具栏按钮点击等发出该消息。所有派生自CCmdTarget的类都有
      能力接收WM_COMMAND消息。
  • 标准消息(WM_XXX)
    • 比如窗口创建,窗口销毁等。所有派生自CWnd的类才有资格接收标准消息。
  • 通告消息(WM_NOTIFY)
    • 这是有控件向父窗口发送的消息,标示控件本身状态的变化。比如下拉列表框选项的改变CBN_SELCHANGE和树形控件的TVN_SELCHANGED消息都是通告消息。
    • Window 9x 版及以后的新控件通告消息不再通过WM_COMMAND传送,而是通过WM_NOTIFY传送,但是老控件的通告消息,比如CBN_SELCHANGE还是通过WM_COMMAND消息发送。
  • 自定义消息
    • 利用MFC编程,可以使用自定义消息。使用自定义消息需要遵循一定的步骤,并需要
      自己编写消息响应函数

MFC

自定义消息

自定义系统唯一消息

发送自定义消息

引用

左值引用

  • 左值持久
  • 左值是变量
  • 左值引用通过&获取

右值引用

  • 右值短暂
  • 右值不能被赋值
  • 右值引用是为了支持移动操作,通过&&来获得右值引用

构造函数

默认构造函数

当没有声明构造函数或者对象在声明的时候没有任何初始化参数的时候,编译器会调用默认构造函数。

但是只要类声明了任何带参数的构造函数,编译器就不会隐式的调用默认构造函数了。

拷贝构造函数

当用一个已经初始化了的自定义对象去初始化另一个新构造的对象时,拷贝构造函数就会被调用。

  • 一个对象以值传递的方式传入函数体
  • 一个对象以值传递的方式从函数返回
  • 一个对象需要通过另一个对象进行初始化

如果在类中没有显示的声明一个拷贝构造函数,那么编译器会形成一个默认的拷贝构造函数,这个拷贝构造函数属于浅拷贝

浅拷贝

如果没有声明一个拷贝构造函数,编译器会形成一个默认的拷贝构造函数。如果类里面有指针数据成员的情况下,在发生拷贝构造函数被调用时,它是位逐次拷贝,也就是说,用来初始化新对象的对象的指针数据成员的值,会赋值给新对象的指针数据成员。后果就是,这两个对象指向同一块内存空间,如果,用来初始化新对象的那个对象释放了这个指针指向的空间,但新对象还是指向那块空间,那新对象的这个指针数据成员就成了一个野指针了。

深拷贝

自定义拷贝构造函数,让类的对象在复制过程中,对指针指向的资源进行单独分配

移动构造函数

移动构造实现的是对象的值的真实的转移:源对象将丢失内容,目的对象将占有内容

对于那些有大量数据需要拷贝的情况,使用移动构造可以提高效率和速度

  • 当使用一个临时变量对对象进行构造初始化的时候,调用移动构造函数
  • 使用std::move(),会讲参数转变为右值

进程间通信

  1. 管道
    1. 无名管道pipe()
    2. 有名管道FIFO mkfifo()
  2. 消息队列
  3. 信号量
  4. 共享内存
  5. Socket
    1. 支持不同主机上的两个进程间的通信
  6. Streams
    1. 支持不同主机上的两个进程间的通信

线程间通信

  1. 全局变量
    1. 使用volatile关键字,每次从内存中读取,而不是因编译器优化而从缓存区读取
  2. 互斥量
  3. 信号量
  4. 事件
  5. 临界区

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2023-02-07
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享