C++(GUI)笔记与总结

前言

你好,我是苏青羽,是一名默默无闻的计算机爱好者。

本笔记是我在学习C++的GUI框架时所总结的学习笔记,主要记录了C++的GUI框架的一些基础知识点,在这里分享给大家,希望通过该笔记能帮助更多的人去理解C++的GUI框架。

笔记中参考了网上的很多博客、公众号、网课、面经等等,这些均在笔记末尾的参考资料中有所展示,大家可自行查看,做更深入的了解。

本笔记主要用于在学习上的复盘,并不适合初学者学习。如果在笔记中遇到了不懂的知识点,一定要去自己看书或者上网查询相关知识点!

如果发现本文有较大的硬性错误、或者是某些内容存在侵权、以及有什么想补充的问题和内容,请点击“关于”,通过里面预留的联系方式同我联系!

本笔记正在实时更新中,若是想获取笔记的最新PDF版以及了解关于我的更多信息,可扫描下方二维码,或微信搜索公众号“苏青羽”关注我!

前提基础

学习本笔记前,请事先掌握以下基础知识

  • C++基础
  • 操作系统
  • 计算机网络
  • 设计模式

Win32

1. 什么是Win32程序?

Win32程序指用C/C++开发的可以调用Windows库函数并运行在Windows环境下的程序。

2. Windows库是什么?

(1) Windows库是微软为程序员所提供的一个函数库,头文件为Windows.h,只要包含了该头文件即可使用里面的API函数。

(2) Windows库的历史悠久,它采用C语言编写,因此该库并没有C++的一些特性。

(3) Windows库由于没有C++特性,它采用了一些其他方法满足程序员所需,如:C语言并不存在布尔类型,Windows库就提供自定义的布尔类型,而它实际上是一个int类型。

(4) 尽管语法遵循C语言规则,但Windows下的C/C++和Linux下的C/C++存在较大差异

3. Win32的应用程序与Linux的差别?

(1) 主要分为控制台程序、窗口程序(GUI)、库程序,在这一点上与Linux并无差别。

(2) Win32的可执行文件后缀均为exe,Linux下的可执行文件一般不需要后缀指明。

(3) Win32的窗口程序的入口函数为WinMain,注意该函数为回调函数

(4) Win32的静态库文件后缀为.lib,动态库文件后缀为.dll,Linux的静态库文件后缀为.a,动态库文件后缀为.so。

4. 说说Win32的开发工具?

(1) 编译器CL.EXE,将源代码编译成目标代码.obj

(2) 链接器LINK.EXE,将目标代码、库链接生成最终文件

(3) 资源编译器RC.EXE , 将资源(.rc文件)编译,最终通过链接器存入最终文件

(4) IDE:Visual Studio,简称VS,集成了上面的编译器、连接器、资源编译器

5. Win32程序开发的字符集问题?

(1) Windows库在原有“char”类型字符的基础上还提供了另一种字符“wchar_t”,它实际上是一个无符号短整型,当我们想以“UNICODE”字符编码程序时,就必须使用它。

(2) “UNICODE”字符编码是一种双字节编码方式,Windows库为了支持它,不仅提供了专属类型,还提供很多专属的字符串处理函数,通常以“w”开头,如“wprintf”。若要使用“UNICODE”声明一个字符串,还必须在字符串前面加上“L”

(3) 为了方便程序员,微软提供了“TCHAR”类型字符以及“__TEXT(字符串)”宏函数。它会根据是否定义UNICODE宏来声明不同的字符类型和字符串。

(4) 对于不同的字符编码,其字符串处理函数名也不一样,为了编程上的方便,一般不将项目设置为“UNICODE”编码,那么所有的字符操作均与原来无异。

6. 说说CALLBACK回调函数?

在Win32程序中,程序员调用Windows库函数的过程被称为Call,Windows库函数调用程序员自定义函数的过程则被称为Callback,而这个程序员自定义的函数就是回调函数。关于回调函数的定义在C++笔记中有更清晰的解释。为了弥补C语言特性上的缺乏(面向对象),Windows库设计了大量的回调函数等待被程序员定义,如WinMain和消息处理函数

7. 什么是句柄?

(1) 在Win32程序中有一种特殊的数据类型——句柄,我们可以用句柄去标识一个程序中的一个实例对象,如线程、窗口等。它的引入是为了解决内存移动所引发的一些问题

(2) 有时候当我们申请一块连续的内存空间时,即使内存中有足够大的空间,但如果这些空间都是间断的不连续的,则会请求失败。为了解决这个问题,Windows允许内存移动,Windows会自动合并空闲内存块以提供足够大的连续内存

(3) 对于内存移动,移动物理内存代价较高,但好处是仅需更改页表映射,程序可以正常访问内存。移动虚拟内存代价较小,但会导致地址更改,无法通过原来的指针访问内存。

使用句柄可以解决该问题,句柄是一种指向指针的指针,它可以代表一个实际对象的地址(实际可能没那么简单,这里是方便理解)。下图是发生虚拟内存移动的两次内存快照。发生内存移动后,某个对象的地址发生了改变,原先的指针失效,会被Windows替换为新指针。但无论如何更改,只要该指针所存放的地址不变,指向该指针的指针值也不会发生改变,句柄也就不会发生变化,自然我们就可以利用句柄实现内存管理

8. WinMain是什么?

(1) WinMain是Win32窗口程序的入口函数,它是一个回调函数,由main函数调用。

(2) Winmain和main不同,它接受4个参数:应用程序当前实例句柄、应用程序上个实例句柄(置NULL)、应用程序命令行参数、窗口显示方式(预设置,由操作系统传入)

9. 说说Win32的窗口类?

(1) 窗口类描述了一类窗口的各种参数,是一种特殊的数据结构,基于窗口类才能创建窗口。

(2) 每个窗口类都必须有独立名称,使用前必须注册到系统,使得操作系统可识别该窗口类。

(3) 窗口类分为3种:

① 系统窗口类:系统已经定义好的窗口类,所有应用程序都可以直接使用。

② 全局窗口类:由用户自己定义,当前应用程序所有模块都可以使用。

③ 局部窗口类:由用户自己定义,当前应用程序中本模块可以使用。

(4) 创建窗口时会通过窗口类名称查找并创建:局部窗口类 -> 全局窗口类 -> 系统窗口类

(5) 点击窗口关闭只会关闭屏幕上的窗口且发送消息WM_DESTROY,内存中依然运行着窗口数据,要想关闭消息循环并结束程序运行,必须发送WM_QUIT消息

10. 窗口处理函数是什么?

(1) 每个窗口类都必须有窗口处理函数,它是一个回调函数,多个窗口类可以共享同一个窗口处理函数。

(2) 窗口处理函数用于处理消息,每个消息最终都会被派发到它所属的窗口对象。所谓的派发就是去调用窗口对象所属窗口类的窗口处理函数,窗口处理函数中封装了处理各种各样的消息的一系列逻辑,然后做出相应的动作以响应消息。

11. 说说Win32的消息及其机制?

(1) 当某个事件发生,如鼠标点击、键盘按下时,Windows会生成一条消息(Message)并发送给某个进程,告诉进程发生了什么事情

(2) 所谓的消息是一种特殊的数据结构,包含一些特定参数。其中消息ID表明消息的含义,而窗口句柄则表明消息所属的窗口对象,帮助系统识别该消息最终会被发送到哪个进程。

(3) 消息分为系统消息用户自定义消息。系统消息是系统预定义的,它的发送是由某些特定事件所触发,程序员只需编写相应的消息处理即可。用户自定义消息是由用户定义的,也是由用户去自行发送和处理的。

(4) Windows使用队列来存放新产生的消息,被称为消息队列。消息队列分为系统消息队列和程序消息队列

(5) 系统消息队列在系统中仅存在一个,而每一个程序/进程都会维护一个独立的程序消息队列。消息产生时会先被存放在系统消息队列中,再由系统定时查询将这些消息进行分类,投递到相应的程序消息队列中,进行被程序所获取。

(6) 消息循环时所抓取的消息只能到程序消息队列中去获取,而不能直接到系统消息队列中。

(7) 大部分的消息都需要通过消息队列完成发送、捕获、处理等流程,如键盘和鼠标消息。特别地,像WM_QUIT消息用于结束消息循环,它必须经过消息队列。

还有一些特殊消息不经过消息队列,而是直接调用消息所属窗口的窗口处理函数。像WM_CREATE,它产生于窗口创建成功但还未显示时,明显无法通过消息循环获取。

12. 说说Win32的消息循环?

(1) 消息循环是一个死循环,要想结束它只能使用WM_QUIT消息。一旦进入该循环,系统将会不断轮询系统中的消息,并将这些消息派发到相应的窗口对象。

(2) 消息循环不仅可以抓取与派发消息,而且还能产生消息,绘画消息和定时器消息的真正产生者就是消息循环。

13. Win32的资源是什么?

(1) 资源是一种可以添加到Win32程序可执行文件中的二进制数据,它主要用于描述图标、图片、菜单、对话框等一系列UI。

(2) 在VS中可以创建资源,并以资源ID去标识一个资源。所有创建的资源都会被转化成特殊的代码文件——rc文件。VS具备了rc文件与图形资源之间相互转化的功能。

(3) 在编译链接时,不管有没有使用资源,资源(rc)文件总是会被链接到可执行文件中去。

(4) 为了在代码中使用资源,VS会提供一个“resource.h”头文件,它是C++代码和资源之间的桥梁,要想使用资源必须包含该头文件。

(5) 在C++代码中标识具体资源的是资源句柄,资源句柄可以通过资源ID获取,之后就可以利用资源句柄设置资源。

14. 顶层菜单和弹出式菜单的区别?

(1) 菜单资源是一个综合性菜单,包含了一个顶层菜单和多个弹出式菜单。

(2) 顶层菜单:只有下拉菜单的功能,无需发送和处理消息,因此不具备菜单项ID。

(3) 弹出式菜单:具备菜单项ID,可以发送消息并做出响应,并且可以作为右键(上下文)菜单使用。

15. 说说字符串资源的作用?

字符串资源的引入主要是为了解决客户需求的变化而导致的代码改动,使用字符串资源可在更改字符串时无需更改程序代码,仅更改资源文件,减少了编译时间。

16. 你能解释下加速键资源是干什么的吗?

(1) 加速键可以通过特殊的按键搭配,使得程序完成相应的功能,如ctrl+c=复制。

(2) 加速键被按下会发送消息,要想从键盘消息中获取加速键消息,必须使用消息翻译函数

17. 说说COMMAND消息?

(1) COMMAND消息是一种特殊的系统消息,当用户点击菜单、按钮、下拉列表框等控件,或者按下加速键,都会发送COMMAND消息。

(2) 当某个控件发出COMMAND消息时,它总是会发送至该控件所属的父窗口,交由父窗口的窗口处理函数响应。

(3) CONMAND消息会携带发送者的控件ID和通知码(单击、双击等等),以区分COMMAND消息的发送者和产生消息时的具体行为。

(4) COMMAND消息的设计使得我们可以通过把一些控件的ID设为公有,而实现函数功能的复用,最常用的就是加速键和菜单,比如ctrl+c=复制。

18. WIN32程序的绘图有什么需要注意的?

(1) 所有的绘图操作仅能在WM_PAINT的消息处理中进行。

(2) 所有的绘图操作都由绘图设备 DC(Device Context)完成,通过DC句柄使用DC。

19. WIN32的对话框和普通窗口的区别?

(1) 对话框不需要注册窗口类,他已被系统提前注册了,直接使用即可。

(2) 对话框的窗口处理函数不能像其他窗口一样最后返回至缺省函数作处理。系统已经实现了对话框的缺省窗口处理函数,程序员自定义的函数仅仅是缺省函数中的一部分扩展代码。若返回至缺省函数处理,会导致无限递归。

(3) 对话框分为模式对话框和无模式对话框,模式对话框显示时会禁止其他窗口和用户交互,而无模式则不会。

20. 说说Win32的静态库和动态库?

(1) 静态库后缀为.lib,可通过在代码中使用#pragma comment( lib, “静态库文件路径”)来使用静态库。

(2) 动态库后缀为.dll,动态库使用前必须在代码中先进行库的导出和导入,动态库使用方式与静态库相同。

(3) 注意,动态库会同时生成.dll和.lib文件。.lib文件只是对.dll文件的映射,但使用动态库必须依赖.lib文件,若动态库没有导出,只会生成.dll文件,此时也无法使用动态库。

21.WIN32的线程互斥怎么实现?

(1) 原子锁:用于保证高级代码中的原子操作在汇编层面也是原子的,如自增自减。这些操作在汇编层可能不止一条指令,且结果可能会被暂存至寄存器,导致多线程环境下的数据错误。使用原子锁可以直接对内存进行操作,且保证操作的线程互斥性。原子锁的效率很高,但只能对原子操作使用,而且必须使用多而难记的原子锁函数

(2) 互斥:最常用的线程互斥机制,可应用到很多线程操作。效率低,应用广泛,使用灵活

22. WIN32的线程同步怎么实现?

(1) 事件:将某个条件定义为事件,线程满足条件将触发事件,唤醒另一线程执行后续操作。

(2) 信号量:带有计数器的事件,使用更灵活,应用更广泛。

23. GetMessage和PeekMessage函数的区别?

(1) 两者都用来从消息队列中获取消息。

(2) GetMessage:阻塞函数,没有消息时会被阻塞。获取消息后直接从消息队列移除消息。

(3) PeekMessage:非阻塞函数,没有消息时直接返回,只查看消息不移除。

24. SendMessage和PostMessage函数的区别?

(1) 两者都用来发送消息。

(2) SendMessage:直接发送消息至相应的窗口,调用窗口处理函数,然后等候消息处理。

(3) PostMessage:发送消息至消息队列,发出后立刻返回,不等候消息执行结果。

MFC

1. 什么是MFC?

微软基础类库,它封装了Windows库提供的各种API,对外提供了面向对象的操作接口,是一个C++类库。

2. MFC窗口程序有几类?

单文档视图架构程序、多文档视图架构程序、对话框应用程序。

3. MFC和Win32的全局函数怎么区分?

(1) 以Afx开头可以确定为MFC库中的全局函数

(2) 以::开头可以确定为Win32的API函数

4. MFC主要用到哪几个类,各自的作用是什么?

(1) CObject类:MFC中绝大多数类的基类,提供了一些基本机制。

(2) CWinApp类:应用程序类,封装了应用程序的信息,控制程序执行流程。

(3) CDocument类:文档类,用以管理数据。

(4) CView类:视图类,用以显示数据。

(5) CFrameWnd类:框架窗口类,提供一个框架,相当于是一个容器,用以存放视图。

5. MFC的入口函数是什么?

MFC与Win32一样,以WinMain为入口函数,但MFC已实现该函数,无需程序员编写

6. MFC是怎么实现面向对象?

(1) C++以类对象去标识一个实例,Windows库以句柄去标识一个实例。MFC在Windows库的基础上建立了句柄到类对象的一一对应关系,使其具备了面向对象的特性。

(2) 类对象->句柄:MFC把句柄保存到一个类对象中,类对象的使用者不必直接使用句柄,而是交由类成员函数去完成相应功能。

(3) 句柄->类对象:MFC维护了一个全局的映射(Map),句柄为key,类对象为value。通过这个映射,拿到某个句柄就可以获取到对应的类对象,进而完成相应功能。

7. MFC的六大机制是什么?

程序初始化、消息映射和消息传递、运行时类型识别(RTTI)、动态创建、串行化

8. MFC程序是如何初始化的?

(1) 程序员必须建立一个CWinApp类的全局对象,WinMain函数会去调用该对象的成员函数去完成一些功能,没有该对象会发生错误。

(2) CWinApp中定义了很多虚函数,这些虚函数会在WinMain函数中被调用,如初始化、消息循环、空闲处理、析构处理,通过继承并重写虚函数,可以自定义程序流程,完成初始化

(3) 值得一提的是,CWinApp中并非所有的函数都是虚函数。虚函数的额外开销会导致性能下降,关于这点可以去查看C++笔记中关于虚函数的描述。

9. 简单说说MFC的消息映射和消息传递机制?

(1) 在Win32中,没有消息映射的概念,我们只是对某个窗口类和窗口处理函数建立了回调关系,然后在窗口处理函数中通过switch语句去处理各种各样的消息。

(2) MFC的消息映射机制使得我们不必实现窗口处理函数,而是建立起某个消息和消息处理函数的映射关系,当消息产生时,系统就会去调用该消息所对应的函数。

(3) MFC定义了一种消息映射表成员结构,把一个消息ID、消息参数、消息处理函数入口绑定在一起。每个窗口类都保存了一个由该结构组成的数组(静态成员),即消息映射表,用以保存当前类感兴趣的消息。

(4) 窗口类可以继承,若派生类对某个消息不感兴趣,应交由基类去解决,因此MFC在窗口类中还插入了两个函数,用来获取基类和自身的消息映射表。通过这种方式就得到了一个由消息映射表所组成的单向链表。

10. MFC的消息映射机制能否使用虚函数机制实现?

(1) 在设计窗口基类(CWnd)时,可以让它对每种消息都定义一个消息响应函数(虚函数)。这样,从CWnd派生的窗口类对所有消息都有了一个空响应,我们要响应一个特定的消息就重载这个消息响应函数就可以了。

(2) 使用虚函数机制的结果是,一个几乎什么也不做的CWnd类要有几百个“多余”的函数,哪怕这些消息响应函数都为纯虚函数,每个CWnd对象也要背负着一个巨大的虚表,严重影响了运行期效率。

(3) MFC的消息映射机制虽然需要为每个类创建静态成员,但由于静态成员的特性(只属于类不属于对象,不占用对象空间),类对象空间并没有因此而增大。不仅如此,静态成员的构建在编译期就可以完成,这也提高了运行期效率。

11. MFC中COMMAND消息的处理顺序?

(1) 所有的MFC窗口底层都是Win32中的窗口类,而他们都与MFC中的一个默认窗口处理函数建立了回调关系。消息产生后,在该函数中再将消息分发到对应的MFC窗口类中去处理。

(2) COMMAND消息也需要执行该函数,但会做特殊处理,按照视图、文档、框架窗口、应用程序的顺序进行处理,若前一个类已经处理该消息,后面则无需继续处理。

12. MFC的运行时类型识别(RTTI)是怎么实现的?

(1) 在MFC设计之初,并没有RTTI机制,因此MFC自己实现了该机制。

(2) MFC对此的设计理念是,设计一个用来储存相关类型信息的单元结构,在每个类中加入该单元结构(静态成员),并且将类型之间全部链接起来,组成一个单向链表。

(3) MFC中将这些操作抽向成了宏,只需定义相关宏即可建立该链表并添加类型结点(前提是必须继承自CObject)

(4) 如果想获取某个类的信息或者去比较两个类型,只需遍历查询该链表即可。

13. MFC的动态创建机制是怎么实现的?

(1) MFC的动态创建机制使得创建对象的行为推迟到了程序运行时。借助该机制可以实现某个函数,它可以创建任何类型的对象,即使该类型是在该函数之后被定义。

(2) 动态创建机制的所有代码被抽象成了宏,只要在类中定义相关宏(前提是必须继承自CObject),该类就允许被动态创建。

(3) 动态创建机制包含了运行时类型识别,以RTTI为基础,在记录类型信息的单元结构中加入了构建对象的函数,这样即可通过类名而在运行时创建对象。

14. 说说MFC的串行化机制?

(1) MFC的串行化机制可以使程序中的各种数据按顺序存储到单一的文件中,然后又能按顺序取出,并构造出不同的对象数据

(2) 可以被串行化的对象必须继承自CObject,并声明串行化宏,最后还必须重写从CObject继承下来的串行化虚函数Serialize

(3) 串行化虚函数Serialize用以实现具体的串行化工作,包括读和写。简单来说就是需要将类对象中的各个成员使用串行化操作(当然前提是这些成员也是可以被串行化的)

(4) 串行化宏包括了RTTI和动态创建机制,因为如果要从文件中读取数据并创建出具体的对象,必须让程序知道某个类的信息并且还能够去创建它,RTTI和动态创建机制正好解决了该问题。

15. 在哪个类的什么函数中进行MFC程序初始化?

在CWinApp::InitInstance()中进行MFC程序初始化

16. 在哪个类的什么函数中进行MFC程序初始化?

(1) 他们两者本质上都是一种容器。框架窗口用来容纳视图窗口,视图用来容纳数据显示。

(2) 在框架窗口中可以通过鼠标点击设置活动视图窗口,只有活动视图窗口才可以处理命令(COMMAND)消息

17. MFC中一些控件ID为STATIC,是什么意思?

MFC中存在某类控件,他们仅用来辅助用户使用程序,不需要具体的对象去标识,如静态文本框,他们的ID均为STATIC。

18. MFC单文档视图架构和多文档视图架构的区别?

(1) 单文档:同一时刻只能操作一个文档。打开文档时,程序会自动关闭当前打开的活动文档。(如Windows自带的记事本程序)。单文档程序使用一个单一变量来保存文档类对象。

(2) 多文档:允许同时操作多个文档。在界面中可以同时打开多个文件(同时也就为每个文件打开一个窗口),并通过切换活动窗口激活相应的文档进行编辑。(如当前流行的文本编辑器Notepad++)。多文档程序使用一个链表来保存多个文档类对象。

19. MFC的MVC架构了解吗?

(1) MVC架构是软件体系中的一种通用架构,MFC就是使用了MVC架构。

(2) MVC架构将软件分为三大部件:模型、视图、控制器(Model View Controller)。

① 模型(Model):负责存储系统的中心数据。

② 视图(View):将信息显示给用户(可以定义多个视图)。

③ 控制器(Controller):负责从视图读取数据,控制用户输入,并向模型发送数据,是应用程序中处理用户交互的部分。

(3) MVC是一种动态的程序设计,简化了程序结构,将信息的内部表示与信息的呈现方式分离开来。比如说可以使用不同的视图对相同的数据进行展示。

(4) 优点:耦合性低;重用性高;可维护性高;有利软件工程化管理。

(5) 缺点:视图对数据的访问效率较慢,不适合中小规模的应用程序。

20. MFC中为什么有时候菜单项会是灰色的?

它没有实现对应的消息处理函数,因此该菜单项无法被点击,呈灰色状态。

21. 说说MFC中的消息分类?

MFC的消息机制把消息细分为三类,对于不同类的消息,其宏和消息处理函数各不同。

(1) 标准windows消息:Windows中的大多数基本消息。声明宏和消息处理函数需要查阅VS帮助手册

(2) 自定义消息:用户自定义的消息。统一采用ON_MESSAGE的方式声明宏,消息处理函数需要接受消息所携带的两个附加参数。

(3) 命令消息:Windows中的Command消息。统一采用ON_COMMAND的方式声明宏,消息处理函数无参数,无须返回值。

QT

1. 什么是QT?

QT是一个跨平台的C++图形用户界面(GUI)应用程序开发框架,支持各大主流操作系统。

2. QT的优点和缺点?

(1) 优点:跨平台,接口简单,具有较高的开发灵活度

(2) 缺点:Qt框架比较庞大、臃肿。

3. QT和MFC的不同?

(1) MFC只能在Windows下运行,而QT可以在多个操作系统上运行,并且可以相互移植。

(2) MFC的运行效率比较高,QT的开发灵活度高

(3) MFC是基于Windows库(C语言)的API而设计的, 这绝非好的面向对象的设计模式,而QT是完全基于面向对象设计的,它的架构具有良好的统一性

4. 说说QT的开发工具?

(1) Assistant:QT助手,相当于VS中的帮助手册

(2) Qmake:QT构建器,用来编译生成makefile文件 以及.pro文件

(3) Designer:QT设计师,用以设计UI界面

(4) Qtcreator:QT创造器,QT的IDE,集成了上述所有开发工具

(5) Uic:转换器,可以将UI文件编译为标准的QT代码文件

5. QT的Pro文件是什么?

Pro文件是Qt项目中的配置文件,每个Qt项目中都必须含有该文件,由Qmake生成。Pro文件也是一种可编辑的代码文件,通过修改该文件,可以设置头文件路径、库文件路径。

6. 了解QT的元对象系统吗?

(1) Qt的元对象系统(meta-object)提供了信号与槽,运行时类型信息,和动态属性系统。

(2) 元对象系统为所有对象提供了一个基类——QObject,只要继承此类,那创建出的对象便可以使用元对象系统。

(3) 在声明类时,将Q_OBJECT宏放置于类的私有区域就可以在类中使能元对象特性,诸如动态属性,信号,以及槽。一般实际使用中,我们总是把Q_OBJECT宏放置在类声明时的开头位置,除此之外我们的类还需要继承QObject类

(4) 元对象编译器(Meta-Object Compiler,缩写moc),为每个QObject的子类提供必要的代码去实现元对象特性。我们可以认为Qt对C++进行了一些拓展,moc则是负责将这些拓展语法翻译成原生的C++语法,之后交给C++编译器去编译。

7. QT的信号和槽是什么?

(1) 信号和槽是QT自行定义的一种通信机制,用来实现对象之间的数据交互

(2) 我们可以控制某个对象发射一个信号,即调用其类中一个特定的成员函数(信号),同时还可能携带有必要的参数。然后会触发和执行与该信号连接的槽函数,进而来完成具体功能。

8. 说说QT的信号-槽机制的实现原理?

(1) 首先,moc会查找头文件中的信号和槽,然后将信号和槽的信息存储到一个类静态变量中,按声明顺序进行存放并建立索引。

(2) 当发现有connect连接时,会将信号和槽的索引信息放到一个map中,彼此配对。

(3) 当调用emit时,调用信号函数,之后QT就会在map中找到所有与信号对应的槽索引。

(4) 信号-槽本质上就是一个“注册-索引”机制。

9. QT的信号-槽机制的优点和缺点?

(1) 类型安全:信号函数和槽函数的参数类型和参数个数必须相同,若不一致,编译器会报错。QT允许一种特殊情况:信号的参数可以比槽函数的参数多,但槽函数的参数也必须与信号前面几个声明的参数保持一致。你可以在槽函数中选择忽略信号传来的数据,但是不能说信号根本没有这个数据,你就要在槽函数中使用。

(2) 松散耦合:信号和槽机制减弱了Qt对象的耦合度。发出信号的Qt对象无需知道是哪个对象的哪个槽接收它发出的信号,它只需要在适当的时间发送适当的信号即可。

(3) 灵活性:一个信号可以关联多个槽,多个信号也可以关联同一个槽。一个信号可以连接到另外的一个信号,实现级联调用。信号和槽的连接可以动态建立和取消。槽函数可使用Lambda表达式(QT5以上支持)。

(4) 速度较慢:信号和槽机制的运行速度比直接调用非虚函数要慢得多。因为在运行时,一旦有信号发出,它就需要定位接收信号的对象和安全地遍历所有槽。但比起它的优点,这样的性能损失可以忽略不计。

10. QT为什么要设计出信号和槽?

(1) QT设计信号-槽是要以它来取代C++中的回调函数(回调函数详细请看C++笔记)

(2) C++中的回调函数存在弊端,如果多个类都关注某个类的状态变化,此时需要维护一个列表,以存放多个回调函数的地址。对于每一个被关注的类,都需要做类似的工作,因此这种做法效率低,不灵活

(3) QT的信号-槽机制很好地消除了回调函数的弊端,但同时在运行效率上也有所损失

11. 说QT的信号-槽机制的局限性?

(1) 信号-槽机制与普通函数的调用一样,使用不当可能产生死循环

(2) 如果一个信号与多个槽相关联,当这个信号被发射时,与之连接的槽的执行顺序将是随机的,并且我们不能指定该顺序

(3) 构造函数不能用在类中信号和槽的声明区域内。

(4) 信号和槽的参数不能出现模板类参数、宏定义、函数指针

12. 说说信号的特点?

(1) 所有的信号声明都是公有的,所以Qt规定不能在signals前面加public,private, protected。

(2) 所有的信号都没有返回值,所以返回值都用void。

(3) 所有的信号都不需要定义

13. QT的槽函数与普通函数的区别?

槽和普通的成员函数几乎没有太多区别,槽函数可以像普通成员函数一样被调用,他们的差别并不在于其语法特性,而在于其功能,槽函数更多体现为对某种特定信号的处理。

14. QT的信号和槽的连接方式有多少种?

(1) Qt::DirectConnection(立即调用):发送信号的时候,所关联的槽函数被发送信号的线程调用,并立即执行(无论这个槽函数所属的对象依附哪个线程)

(2) Qt::QUeuedConnection (异步调用):信号发送至目标线程的事件队列中,等待被执行,当前线程继续往下执行。

(3) Qt::BlockingQueuedConnection (同步调用):信号发送至目标线程的事件队列中,当前线程阻塞等待槽函数执行完成之后再继续往下执行。

(4) Qt::AutoConnection (默认连接):当所属槽函数的对象与发送信号处于同一个线程的时候使用立即调用,否则使用异步调用。

(5) Qt::UniqueConnection (单一连接):连接只能存在一个,重复连接会失败。

15. QT的事件是什么?

在Qt中,当用户或系统触发了一个动作时,会产生一个对应的事件。事件比信号更原始,QT控件中的信号和槽都依赖于Qt的事件处理机制。比如当按下某个按钮控件时,首先产生对应事件,在事件中再进行信号的发射,进而触发槽函数。

16. 说说事件的处理机制?

(1) 在Qt中,事件被封装成对象,所有的事件对象类型都继承自抽象类QEvent当事件发生时,Qt 将创建一个事件对象。

(2) Qt 使用事件队列对所有发出的事件进行维护。新事件产生后,会被追加到事件队列的尾部,等待系统进行处理。事件也可以不进入事件队列,而是直接处理,这类似于MFC中的消息队列。

(3) 事件最终会被QT分发到某个对象中,即调用QObject类中的虚函数event(),其参数(QEvent)标识了具体的事件类型,它并不直接处理事件,而是根据事件类型分发给不同的事件处理器。由于该函数是虚函数,一旦子类没有去重写处理,就会向父类进行传递。

(4) 在Qt的GUI开发中,Qt的窗口类覆盖了基类中的event()虚函数,并根据具体事件定义了各种具体的事件处理虚函数,在event函数中会根据事件类型去调用这些事件处理虚函数。程序员可自行设计窗口类去继承Qt的窗口类,并重写其中的事件处理虚函数,从而实现自定义的事件处理效果。

17. 事件和信号的区别?

(1) 当我们设计一个控件时,我们需要关心,当控件发生事件时需要定义什么样的处理去响应该事件,这其实就是一个处理事件的过程。

(2) 当我们使用一个控件时,我们需要关心控件上的哪些动作会触发什么信号(本质是事件,只是由控件的设计者设置成会发送某个信号),然后由我们去连接相应的槽函数响应这些信号,这就是处理信号的过程

(3) 事件类似于 Windows 里的消息,它的发出者一般是窗口系统。信号和槽机制相对而言比较“高层”,它的发出者一般是对象

18. QT的信号-槽和MFC的消息映射之间的异同?

(1) 两者都使用了观察者模式,实现了消息/信号和执行函数的绑定,并且可以实现跨线程的调用。

(2) MFC的消息映射仅是Windows消息处理过程中的最后一部分,对应到QT中相当于QT事件处理机制中的QObject::event()。而QT的信号-槽机制实际上是一种对象间通信机制,用于实现对象之间的数据交互,位于QT的事件机制之上。QT的信号-槽和MFC的消息映射在本质上是完全不同的。

(3) MFC实现消息映射是为了避免在处理消息时使用虚函数,从而提升运行时期性能。MFC基本上做到了。MFC建立消息映射的过程根本就是在编译时期完成的,不占用运行时期的时间。QT的信号-槽相对更加复杂,复杂的处理过程使得效率和性能上并没有MFC高,还会影响运行时速度。

(4) MFC只可以在编译期构造消息处理函数与消息的绑定关系,而QT支持运行时期动态建立和断开信号与槽的连接。

(5) QT的信号-槽支持多种形式的槽,支持多种形式的连接,比较自由。MFC在这一点上就不如QT,只支持函数指针。

19. 常见的事件有哪些?

绘图事件、定时器事件、鼠标和键盘事件

20. 说说Qt中的内存管理机制(对象树)?

(1) Qt提供了一种内存管理机制,它能够自动、有效地组织和管理继承自QObject的Qt对象,被称为对象树

(2) Qt库中的很多类都以QObject作为它们的基类。QObject的对象总是以树状结构组织自己。当我们创建一个QObject对象时,可以指定其父对象(也被称为父控件),新创建的对象将被加入到父对象的子对象(也被称为子控件)列表中。

(3) 当父对象被析构时,这个列表中的所有子对象会被析构。不但如此,当某个QObject对象被析构时,它会将自己从父对象的列表中删除,以避免父对象被析构时,再次析构自己。

(4) 通常在最上层会有一个根QObject对象,它管理了程序中所有的QObject对象。Qt会自动设定它的父对象为QApplication,当QApplication对象销毁时,所有的QObject对象也就被清除了,无需手动清理。

(5) 值得注意的是,虽然可以手动释放掉这些被管理的QObject对象,但如果此时该对象正在接收事件,很有可能出现意料之外的错误。如果一定要这样做,使用QObject的deleteLater函数会更加安全。

21. Qt中的QApplication类有什么用?

(1) 对于任何使用Qt的GUI应用程序,都必须有且只有一个QApplication对象

(2) QApplication类用于管理GUI应用程序的控制流和主设置。

(3) 它使用用户的桌面设置来初始化应用程序,并且跟踪这些属性,以防用户全局更改桌面。

(4) 它负责了整个Qt程序中的事件循环和事件处理。

22. Qt中的exec和show的区别?

(1) 在Qt开发过程中,一般会使用exec()和show()来显示窗口

(2) exec用来显示模式窗口。即当前程序中只能操作该窗口,其余窗口不能再操作,主程序被阻塞;只有关闭该窗口后阻塞才会停止。

(3) show用来显示非模式窗口。主程序不会被阻塞,可以任意操作。

(4) show也可以用来显示半模式窗口。该模式下虽然只能操作该窗口而不能操作其他窗口,但是代码仍然可以接着运行,并不会被真正阻塞。

23. Qt和MFC在UI设计时的区别?

(1) MFC:

① MFC中将UI界面、图片、音频等统称为资源,并由资源文件进行管理。

② 所有的资源都有一个唯一的资源ID进行标识,在MFC中若想操作该资源,必须将这个资源的资源ID与某个类对象进行绑定,再通过类对象进行操作。

③ 资源绑定方式有两种,一是与控件类进行绑定,如按钮、下拉框就常用该方式。二是与某个基本类型进行绑定,如编辑框即可与相应的字符串进行绑定。

④ 资源文件会由资源编译器编译并最终链接至可执行文件中。

(2) Qt:

① Qt在这一点上进行了细分,把控件、菜单等划分为UI文件,而将图片、音频等划分为资源文件

② UI文件最终都会被转化为Qt代码文件(以ui开头),所以无需进行类对象绑定操作,Qt自动为所有控件生成相应的类对象(控件类),在代码中可直接使用这些类对象。

③ UI文件转化成的Qt代码文件和资源文件最终都会自动编译链接至可执行文件中

更新记录

更新日期 更新详情
(2023年01月27日) 基本以B站达内教育的网课为基础,主要总结了Win32程序中的相关内容
(2023年04月22日) 在原笔记的基础上添加了MFC、QT等相关内容,并改名为C++(GUI)笔记。删减了原笔记中大量过于繁杂的内容,对笔记进行重新排版,现在该笔记主要总结了C++GUI编程中几个重要框架的基本原理,而不去对这几个框架的使用作具体说明了.
(2023年08月31日) 将各个大板块重新编号,现在各个版块都有独立的题目编号,互不干扰。将更新记录中的版本号替换为年份日期,取消版本号机制,方便记录更新。QT板块增加第23问。
(2023年09月17日) 修改首页文字布局,统一化布局。修改前言。添加前提基础模块。更改正文和标题字体。所有的更新日期都添加前置0,统一长度。修复页码错误。

参考资料

《Windows32应用编…..》:https://www.bilibili.com/video/BV1Zg411Y7ot/

《新版MFC编程全套精品视频》:https://www.bilibili.com/video/BV1QA411g7dX

《QT图形框架编程开发……》:https://www.bilibili.com/video/BV1Wf4y1Y7uh

《Win32编程基础之资源》:https://zhuanlan.zhihu.com/p/161343829

《windows消息机制》:https://blog.csdn.net/weixin_45004203/article/details/123066202

《究竟什么是Windows句柄》:https://blog.csdn.net/qq_31967569/article/details/115313755

《深入了解Windows句柄到底是什么》:https://www.cnblogs.com/mlgjb/p/8588028.html

《WinMain的基本流程》:https://blog.csdn.net/hk121/article/details/80960086

《WM_COMMAND消息》:https://blog.csdn.net/weixin_40237617/article/details/81010987

《MFC六大核心机制之五、六:消息映射和命令传递》:http://www.jizhuomi.com/software/275.html

《MFC六大核心机制之二:运行时类型识别(RTTI)》:http://www.jizhuomi.com/software/269.html

《MFC面试题总结》:https://blog.csdn.net/seuliujiaguo/article/details/39080889

《单文档/多文档……》:https://www.cnblogs.com/hao-hong-sheng/p/8513280.html

《QT和MFC的优缺点比较》:https://blog.csdn.net/qq_43475285/article/details/113894729

《C++ Qt常用面试题……》:https://blog.csdn.net/qq_33462307/article/details/108998579

《Qt - 信号与槽的连接方式》:https://blog.csdn.net/weixin_41937297/article/details/121584841

《请问QT的信号-槽机制……》:https://www.zhihu.com/question/513036823/answer/2514846978

《QEvent: QT事件处理》:https://blog.csdn.net/qq_21980099/article/details/119800165

《Qt 常用面试题整理(不定时整理)》:https://blog.csdn.net/qq_28928005/article/details/128778057

《Qt:QApplication类》:https://blog.csdn.net/zhizhengguan/article/details/115708624


C++(GUI)笔记与总结
http://example.com/2023/09/17/C++(GUI)笔记与总结/
作者
苏青羽
发布于
2023年9月17日
许可协议