QT常见面试题,基础知识偏多
Posted GreenArrowMan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT常见面试题,基础知识偏多相关的知识,希望对你有一定的参考价值。
关注公众号“程序猿小哥”,请扫描下面的二维码。
自定义控件:
应该做过吧?能举几个例子吗?还有其他的吗?
你觉得自定义控件的方法主要是哪些?
答:从外观设计上:QSS、继承绘制函数重绘、继承QStyle相关类重绘、组合拼装等等
从功能行为上:重写事件函数、添加或者修改信号和槽等等
QSS:
QSS平时使用的多吗?能举几个例子吗?
都是如何使用,能说说吗?
答:1.将QSS统一写在一个文件中,通过程序给主窗口加载;
2.写成一个字符串中,通过程序给主窗口加载;
3.需要使用的地方,写一个字符串,加载给对象;
4.QT Designer中填写;
事件机制:
QT程序是事件驱动的,事件到处都可以遇到。能说说平时经常使用到哪些事件吗?
常见的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版本:
请问使用的QT版本是?有没有使用过QT4?QT5的信号槽与QT4相比有什么改进?
答:*编译期:检查信号与槽是否存在,参数类型检查,Q_OBJECT是否存在
*信号可以和普通的函数、类的普通成员函数、lambda函数连接(而不再局限于信号函数和槽函数)
*参数可以是 typedef 的或使用不同的namespace specifier
*可以允许一些自动的类型转换(即信号和槽参数类型不必完全匹配)
信号槽机制:
能说下你的理解吗?
能用什么方法替代?槽函数可以是虚函数吗?
答:回调函数。可以。
信号槽同步与异步:
信号槽是同步的还是异步的?分别如何实现?
答:通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:Qt支持6种连接方式,其中3中最主要:
1.Qt::DirectConnection(直连方式)(信号与槽函数关系类似于函数调用,同步执行)
当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。
2.Qt::QueuedConnection(排队方式)(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)
当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。
3.Qt::AutoConnection(自动方式)
Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。
4.Qt::BlockingQueuedConnection(信号和槽必须在不同的线程中,否则就产生死锁)
这个是完全同步队列只有槽线程执行完成才会返回,否则发送线程也会一直等待,相当于是不同的线程可以同步起来执行。
5.Qt::UniqueConnection
与默认工作方式相同,只是不能重复连接相同的信号和槽,因为如果重复连接就会导致一个信号发出,对应槽函数就会执行多次。
6.Qt::AutoCompatConnection
是为了连接Qt4与Qt3的信号槽机制兼容方式,工作方式与Qt::AutoConnection一样。
如果这个参数不设置的话,默认表示的是那种方式呢?
没加的话与直连方式相同:当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。在这个线程内是顺序执行、同步的,但是与其它线程之间肯定是异步的了。如果使用多线程,仍然需要手动同步。
多线程:
多线程使用的多吗?能简单说说吗?QT多线程有两种方法实现。
知道死锁吗?死锁是如何产生的?
答:死锁的产生有如下四个必要条件
1. 资源是互斥的,同一时刻只能有一个进程占有该资源
2. 资源的释放只能有该进程自己完成
3. 线程在获取到需要资源之前,不会释放已有资源
4. 存在这么一条循环等待的队列,线程T1,T2,T3…, Tn
T1持有自己的资源请求T2的资源,….Tn持有自己的资源请求T1的资源
线程同步的方法有哪些?
答:1.互斥量(QMutex)
QMutex m_Mutex; m_Mutex.lock(); m_Mutex.unlock();
2.互斥锁(QMutexLocker)
QMutexLocker mutexLocker(&m_Mutex);
从声明处开始(在构造函数中加锁),出了作用域自动解锁(在析构函数中解锁)。
3.等待条件(QWaitCondition)
QWaitCondtion m_WaitCondition; m_WaitConditon.wait(&m_muxtex, time);
m_WaitCondition.wakeAll();
4. QReadWriteLock类
》一个线程试图对一个加了读锁的互斥量进行上读锁,允许;
》一个线程试图对一个加了读锁的互斥量进行上写锁,阻塞;
》一个线程试图对一个加了写锁的互斥量进行上读锁,阻塞;、
》一个线程试图对一个加了写锁的互斥量进行上写锁,阻塞。
读写锁比较适用的情况是:需要多次对共享的数据进行读操作的阅读线程。
QReadWriterLock 与QMutex相似,除了它对 "read","write"访问进行区别对待。它使得多个读者可以共时访问数据。使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。
5. 信号量QSemaphore
但是还有些互斥量(资源)的数量并不止一个,比如一个电脑安装了2个打印机,我已经申请了一个,但是我不能霸占这两个,你来访问的时候如果发现还有空闲的仍然可以申请到的。于是这个互斥量可以分为两部分,已使用和未使用。
6.QReadLocker便利类和QWriteLocker便利类对QReadWriteLock进行加解锁
设计模式:
设计模式平时有使用到吗?能不能说下常见的设计模式有哪些?能不能说说大致的概念?能不能具体说下工作中如何使用的?
答:总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
动态库:
工作中有没有使用过动态库和静态库?能不能简单说下两者的区别?
答:静态库:在链接阶段将汇编生成的目标文件.o与引用库一起链接打包到可执行文件中,可简单看成(.o或者.obj文件的集合)。(1)对函数库的链接是放在编译时期完成的(2)程序在运行时与函数库没有瓜葛,移植方便(3)浪费空间和资源
动态库:(1)将库函数的链接载入推迟到程序运行时期(2)可以实现进程间的资源共享(因此也称为共享库)(3)将一些程序升级变得简单(4)可以真正的做到链接载入完全由程序员在程序代码中控制(显示调用)
动态库一般也会有个lib文件,那么和静态库lib文件有什么区别?
动态库中的.lib文件叫做导入库,对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
静态库中的.lib叫做静态库,本身就包含了实际执行代码、符号表等等
TCP/UDP/HTTP(S):
TCP/UDP有使用过吗?能结合工作具体说说吗?
HTTP协议有使用过吗?QT5中使用的相关联的主要的几个类?
答:QNetworkAccessManager/QNetworkRequest/QNetworkReply。
算法:
平时使用算法比较多吗?能简单说下快排的思想吗?时间复杂度是多少?
答:基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
时间复杂度:平均为O(nlogn),最好为O(nlogn),最差为O(logn2)
数据库:
工作中有使用数据库吗?mysql使用多吗?
串口通讯:
有使用到窗口通讯吗?能简单说下具体应用吗?
SVN/Git:
平时团队或者公司是如何管理代码的?使用什么工具?
定位问题:
请问下,如果软件除了问题(Bug),如何快速定位?主要方法有哪些?
答:打印输出/代码调试/日志记录/分析工具/找同事讨论。
1、二分法定位技巧
无论是有多复杂的代码,利用二分法定位技巧一般都是可以定位到问题所在。
从二分法定位技巧可以延伸出一些具体的处理bug的方法,比如:对输入数据二分、对代码版本二分、注释掉部分代码、在不同位置插入试探性代码、对运行环境二分。
2、IDE调试
IDE的VS debug的功能简直就是立竿见影。它可以加断点,单步调试。
单步调试可以让我们对代码逻辑,执行顺序,以及各种中间结果更加清晰。
至于本身容易出错的BUG,用IDE调试简直是再合适不过了。
3、重新读一遍程序
相对新手程序员来说,如果代码出现bug,可以重新读一遍程序。这种方法是最有效、最快速的 Debug 方式。
4、必杀,重写一遍
如果你发现无论如何也找不到BUG,而且代码只是复杂,本身不是很长,直接重写代码吧!
5、小黄鸭调试法
小黄鸭调试法是程序员们经常使用的调试代码方法之一。
小黄鸭不懂程序,所以我们可以向他解释每一行程序的作用,以此来激发灵感。
IDE(集成开发环境):
Windows系统主流IDE:QT Creator、Visual Studio等
Mac系统主流:XCode等
问题:平时主要使用的IDE是什么?有没有做过QT跨平台?
引用和指针有何区别:
1.指针是一个对象,而引用仅是一个对象的别名
2.引用使用时无需解引用,指针需要
3.引用只能在定义时初始化一次,而指针可变
4.引用不能为空,指针可以为空
5.有多级指针没有多级引用
6.不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间,指针会开辟内存空间
7.引用自加改变引用值的内容,指针自加改变指针的指向
8.sizeof含义不同,引用结果为引用类型的大小,指针始终是地址空间所占大小
9.引用比指针使用起来相对更安全
虚函数
什么情况下使用虚函数?和纯虚函数有什么区别?虚析构函数的作用是什么?(虚函数表)
答:虚函数的主要作用是“运行时多态”。虚析构函数的作用在于使用delete删除一个对象时,能确保析构函数被正确的执行。
区别:
1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class)。
2. 虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用,而纯虚函数必须在子类(sub class)中实现该函数才可以使用,因为纯虚函数在基类(base class)只有声明而没有定义。
3. 虚函数和纯虚函数都可以在子类(sub class)中被重载,以多态的形式被调用。
4. 虚函数和纯虚函数通常存在于抽象基类(abstract base class -ABC)之中,被继承的子类重载,目的是提供一个统一的接口。
5. 虚函数的定义形式:virtual method body
纯虚函数的定义形式:virtual = 0;
在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind),而且被两者修饰的函数生命周期(life recycle)也不一样。
6. 虚函数必须实现,如果不实现,编译器将报错,错误提示为:
error LNK****: unresolved external symbol "public: virtual void __thiscall
ClassName::virtualFunctionName(void)"
7. 对于虚函数来说,父类和子类都有各自的版本。由多态方式调用的时候动态绑定。
8. 实现了纯虚函数的子类,该纯虚函数在子类中就编程了虚函数,子类的子类即孙子类可以覆盖
该虚函数,由多态方式调用的时候动态绑定。
9. 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的
函数。
10. 多态性指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
a.编译时多态性:通过重载函数实现
b 运行时多态性:通过虚函数实现。
11. 如果一个类中含有纯虚函数,那么任何试图对该类进行实例化的语句都将导致错误的产生,因为抽象基类(ABC)是不能被直接调用的。必须被子类继承重载以后,根据要求调用其子类的方法。
数据结构,容器
定时器
1. QObject::startTimer和timerEvent
2. QTimer
精度和定时器分辨率:The accuracy of timers depends on the underlying operating system and hardware. Most platforms support a resolution of 1 millisecond, though the accuracy of the timer will not equal this resolution in many real-world situations.
The accuracy also depends on the timer type. For Qt::PreciseTimer, QTimer will try to keep the accurance at 1 millisecond. Precise timers will also never time out earlier than expected.
For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up earlier than expected, within the margins for those types: 5% of the interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
All timer types may time out later than expected if the system is busy or unable to provide the requested accuracy. In such a case of timeout overrun, Qt will emit activated() only once, even if multiple timeouts have expired, and then will resume the original interval.
以上是关于QT常见面试题,基础知识偏多的主要内容,如果未能解决你的问题,请参考以下文章