QT 常见面试题
1、在Qt当中,多线程环境下,信号槽分别是在什么样的线程中执行?如何控制?
参考答案:
通过connect(...)第5个参数控制信号槽执行所在线程
connect(...)它的连接方式:队列连接、自动连接和直接连接
- 队列连接 Qt::QueuedConnection
- 自动连接 Qt::AutoConnection
- 直接连接 Qt::DirectConnection
2、在Qt开发当中,UDP协议当中的UdpSocket通讯流程?
参考答案:
在Qt当中提供QUdpSocket类来进行UDP数据报发送和接收数据(IP地址和端口)。
流程:
A创建QUdpSocket套接字对象---》B如果需要接收数据,必须绑定端口--->C发送数据使用writeDatagram,接收数据使用readDataGram
3、在Qt开发当中,TCP协议通讯流程
参考答案:
- 服务器端:创建QTcpServer对象---》监听list(IP地址和端口)--》等待客户端连接成功后发送newConnect信号---》直接在newConnection信号槽函数中,调用nextPendingConnection函数获取新的连接QTcpSocket对象----》连接QTcpSocket对象的readRead信号---》在readRead信号槽函数使用read接收数据---》调用write函数来发送数据
- 客户端:创建QTcpSocket对象---》当对象与服务器连接成功时会发送connected信号---》调用函数connectToHost连接服务(IP地址和端口)---》connected信号的槽函数开始发送数据---》使用write发送数据,使用read函数接收数据。
4、Qt 信号槽机制及其优点与缺点
- 信号:所谓信号槽(观察者模式),信号的本质就是事件。信号展现方式就是函数,当某一事件发生之后,则发出一个信号(Signal)
- 槽:就是对应信号响应函数,槽就是一个函数,槽函数与普通函数区别:槽函数可以与一个信号关联,当信号被射时,关联的槽函数被自动执行处理。信号和槽关联使用的是QObject::connect()函数进行实现。
信号和槽机制连接方式:
- 一个信号可以跟另一个信号相连
- 同一个信号可以跟多个槽相连
- 同一个槽可以响应多个信号
信号和槽的本质
回调函数。信号或是传递值,或是传递动作变;槽函数响应信号或者接收值,或是根据动作变化来做出对应操作。
信号与槽的优缺点
优点:
- 灵活性。一个信号可以关联多个槽,或多个信号关联同一个槽
- 类型安全。需要关联的信号槽的签名必须是等同的。即信号的参数类型和参数个数同接受改信号槽的参数类型和参数个数相同。若信号和槽签名不一致,编译器会报错。
- 松散耦合。信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是那个对象的那个槽接受它发出的信号,它只需在适当的时间发送适当的信号即可,而不需要关系是否被接受和哪个对象接受了。Qt就保证了适当的槽得到了调用,即使关联的对象在运行时被删除了。程序也不会崩溃。
缺点:
速度比较慢
一般情况,通过传递一个信号来调用槽函数将会比直接调用非虚函数运行速度慢10倍,原因:
- 多线程的时候,信号可能需要排队等待
- 编组/解组传递参数
- 安全地遍历所有关联
- 需要定位接受信号的对象
5、在Qt当中,文件流(QTextStream)和数据流(QDataStream)
参考答案:
- 文件流:操作轻量级数据,数据写入文本之后是以文本的方式展示
- 数据流:通过数据流可以操作各种数据类型(包括对象,存储到文件中的数据为二进制)
- 文件流和数据流都可以操作磁盘文件,也可以操作内存数据。通过流对象可以将对象打包到内存,进行数据的传输。
6、C++语言中,拥有3个智能指针分别是什么
参考答案:
- share_ptr:同一个内存存储空间每多一个指针指向就计数加1,如果计数为0,则释放内存空间
- unique_ptr:计数只能为1,没有拷贝构造函数
- weak_ptr:指向内存存储空间而没有使用权
7、C++协程
参考答案:
- 线程分类:内核态线程、用户态线程
- 协程本质:处理自身挂起和恢复的用户态线程。协程切换要比线程切换速度更快,适合处理IO密集型任务。
- 协程分类:有栈协程(改变函数调用栈)和无栈协程(基于状态机或闭包)
8、互斥锁、读写锁、自旋锁
参考答案:
Mutex
是失眠等待类型的锁,当线程抢占互斥锁失败的时候,线程则陷入休眠。
- 优点:节省CPU资源
- 缺点:休眠唤醒会消耗一定时间
读写锁(read-write lock)
又称为”共享-独占锁“。对于临界区区分读和写,读共享,写共享。
适用场景:多读少写
自旋锁(spinlock)
忙等待。不会引起线程休眠
9、Qt当中,智能指针有哪些?
参考答案:
- QSharePointer:对拥有的内存资源的引用计数,引用计数下降到0时,内存资源则被释放。
- QScopedPointer:内存数据只在一个地方被调用。
- QPointer:指向QObject及派生类的对象。
9、Qt当中,多线程使用方法
方法一:
- 创建一个类从QThread类派生
- 在子线程类中重写run函数,将处理操作写入改函数中
- 在主线程中创建子线程对象,启动子线程,调用start()函数
方法二:
- 将业务处理抽象成一个业务类,在该类中创建一个业务处理函数
- 在主线程中创建一个QThread类对象
- 在主线程中创建一个业务对象
- 将业务对象移动到子线程中
- 在主线程中启动子线程
- 通过信号槽的方式,执行业务类中的业务处理函数
简述:两种基本方式,一种QObject继承,将对象MoveToThread(&QThread),另一种是QThread继承,并重写run函数
多线程使用注意事项:
- 业务对象,构造的时候不能指定父对象
- 子线程中不能处理ui窗口(ui相关类)
- 子线程中只能处理一些数据类型相关的操作,不能涉及窗口
Qt程序是事件驱动的,常用事件:
- 键盘事件:按键按下和松开鼠标事件;
- 鼠标事件:鼠标移动,鼠标按键的按下和松开
- 拖放事件:用鼠标进行拖放
- 滚动事件:鼠标滚动
- 绘屏事件:重绘屏幕的某些部分
- 定时事件:定时器倒时
- 焦点事件:键盘焦点移动进入和离开事件鼠标移入widget之内,或是移出
- 移动事件: widget的位置改变 大小改变事件: widget的大小改变
- 显示和隐藏事件: widget显示和隐藏 窗口事件: 窗口是否为当前窗口
QT事件机制有几种级别的事件过滤吗?能大致描述下吗?
参考答案:
根据对Qt事件机制的分析, 我们可以得到5种级别的事件过滤,处理办法. 以功能从弱到强, 排列如下:
1)重载特定事件处理函数.
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent() 这样的特定事件处理函数.
2)重载event()函数.
通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件(比如:LayoutDirectionChange)时,evnet()也很有用,因为这些函数没有相应的特定事件处理函数. 当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件.
3) 在Qt对象上安装事件过滤器.
安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)
首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.
然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码.
4) 给QAppliction对象安装事件过滤器.
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个 eventFilter(). 在debug的时候,这个办法就非常有用, 也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. ( 在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃)
5) 继承QApplication类,并重载notify()函数.
Qt 是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法. 通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件。
关于QT版本,QT5的信号槽与QT4相比有什么改进
1、编译期:检查信号与槽是否存在,参数类型检查,Q_OBJECT是否存在
2、信号可以和普通的函数、类的普通成员函数、lambda函数连接(而不再局限于信号函数和槽函数)
3、参数可以是 typedef 的或使用不同的namespace specifier
4、可以允许一些自动的类型转换(即信号和槽参数类型不必完全匹配)
更多推荐
所有评论(0)