信号的本质:
信号通常是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号
信号的本质是事件, 但是是以函数的形式存在,在Qt中信号相对应的函数,只有声明没有定义
信号的呈现形式是一个函数,也就是说某个事件产生了,Qt框架就会调用某个对应的信号函数,通知使用者
- Qt中信号的发出者是某个实例化的类对象,对象内部可以进行相关事件的检测.
槽的本质:
槽函数是Qt中一类可以对Qt框架中产生的信号进行处理的函数,另外槽函数也可以做为类的普通成员函数来使用
- Qt中槽函数的所有者也是某个类的实例对象
信号和槽之间的关系:
通常在不做任何处理时,Qt中的信号和槽是独立的,没有关系;
因为某种需要我们需要将他们连接在一起: 这时候用到的就是
QObject
类中的connect
函数,将信号与槽连接在一起
QMetaObject::Connection QObject::connect(
const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection);
参数:
- sender: 发出信号的对象
- signal: 属于sender对象, 信号是一个函数, 这个参数的类型是函数指针, 信号函数地址
- receiver: 信号接收者
- method: 属于receiver对象, 当检测到sender发出了signal信号, receiver对象调用method方法,信号发出之后的处理动作
- type: 连接方式
// 参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
关于connect()函数
的第5个参数:ConnectionType
首先
ConnetionType
具有默认参数:AutoConnection
,第五个参数主要是解决多线程情况下信号与槽之间的配合关系的,指定槽函数在那个线程中执行①
AutoConnection
:自动连接。如果信号与槽(信号的发送者和接收者)位于同一个线程,等同于直接连接;如果信号与槽位于不同的线程中,等同于队列连接②
DirectConnection
:直接连接。当信号被发射后,槽函数立即执行处理,无论槽函数的所有者属于哪个线程;槽函数都将在信号发送者所在的线程执行③
QueuedConnection
:队列连接。信号被放入接收者所在线程的信号队列中,等待线程取到该信号后再执行槽函数,也即槽函数执行在接收者对象所在的线程④
BlockingQueuedConnection
:阻塞队列连接。槽函数的调用时机同队列连接;不同的是该模式下,信号发送者所在的线程会阻塞,一直等到该信号被槽函数处理并返回才解除阻塞(有点类似MFC中的SendMessage()
)⑤
UniqueConnection
:单一连接。该参数可以与其余的四个参数一起使用,用于避免重复连接
槽函数的本质是一个回调函数,在某个信号产生之后,由Qt框架来执行调用工作
也即信号和槽本质上都是函数,当发生了某个事件之后,这个事件关联的对象会根据事件的类型发出信号
因为我们已经使用connnect函数将信号和槽函数关联起来,因此Qt框架会帮我根据信号调用信号接收者对应的槽函数,这类似一个回调函数的形式
自定义信号:
signals
关键字指定自定义槽函数:
类成员函数
,全局函数
,静态函数
,Lambda表达式
野指针:野孩子、野人,从来没有被教育过,也即指针没有被初始化
悬空指针:孤儿,有过爸爸妈妈,但是都去世了,是孤儿,也即指针指向的内存被释放了,但是没有及时地置空
SendMessage()
与PostMessage()
的区别LRESULT SendMessage(
[in] HWND hWnd,
[in] UINT Msg,
[in] WPARAM wParam,
[in] LPARAM lParam
);
SendMessage(阻塞的)
函数用于给一个窗口或几个窗口发送一个指定的消息,并调用窗口处理程序处理该消息,直到该消息被处理之后函数才会返回
BOOL PostMessageA(
[in, optional] HWND hWnd,
[in] UINT Msg,
[in] WPARAM wParam,
[in] LPARAM lParam
);
PostMessage(非阻塞的)
函数是用于把一个消息放进指定窗口的工作线程所关联的消息队列中,然后立即返回,不等待线程去处理该消息
是使用IEEE 754浮点表示法
对于一个float,是4字节32位,从高位到低位依次是
符号
、阶码
、尾数
(1 ,8,23)符号位决定了这个数的正负
阶码是权重
尾数是一个二进制小数
double是64位(1,11,52)
①switch…case…只能用于case值为常量的分支结构,而if…else…更加灵活。
②if判断条件为逻辑表达式,可以是布尔类型的合法表达式、可以是常量、枚举等。而switch 通常处理算术表达式,或字符。
③switch 进行一次条件判断后直接执行到程序的条件语句。而if…else 有几种条件,就得判断多少次
④相比if语句,switch语句是以空间换时间的分支结构。因为它要生成跳转表,所以占用较多的代码空间。当case常量分布范围很大但实际有效值又比较少的情况,switch…case的空间利用率将变得很低。
⑤分支较多时,使用switch的效率高于if,除非第一个if条件就为真
switch (expression)
{
case /* constant-expression */:
/* code */
break;
default:
break;
}
①全局对象一般在main()函数之前初始化,因此可以在全局对象的构造函数中调用某些函数
②main函数的参数argc、argv会在main执行之前进行传递
③类的静态成员变量一般在main()函数执行前就初始化
容器适配器:
queue、stack
红黑树定义:用红色和黑色标记的自平衡二叉搜索树, 所谓平衡指的不是完全平衡,而是大致平衡
查询、插入、删除的时间复杂度:
O(logn)
红黑树的性质:
- 首先是一个二叉搜索树(又称为有序二叉树,定义如下)
- 若任意节点的左子树不为空,则左子树上所有节点的值均小于他的根节点的值
- 若任意节点的右子树不为空,则右子树上所有节点的值均大于他的根节点的值
- 任意节点的左右子树也分别为二叉搜索树。
root
和Nil节点
是黑色- 不存在两个相邻的红色节点,相邻指的是父子相邻的关系
- 从任意节点到其每个叶子节点的所有简单路径上都有相同数目的黑色节点