C++面试题记录(Qt上位机方向)

简述Visual C++ 、Win32 API和MFC之间的关系?

(1) Visual C++是一个以C++程序设计语言为基础的、集成的、可视化的编程环境;
(2) Win32 API是32位Windows操作系以C/C++形式提供的一组应用程序接口;
(3) MFC是对Win32 API的封装,简化了开发过程。

Qt 的核心机制(元对象系统)

Qt的元对象系统(meta-object)提供了用于内部对象通讯的信号与槽(signals & slots)机制,运行时类型信息,以及动态属性系统(dynamic property system)。 整个元对象系统基于三个东西建立:

  1. QObject类为所有对象提供了一个基类,只要继承此类,那创建出的对象便可以使用元对象系统。
  2. 在声明类时,将Q_OBJECT宏放置于类的私有区域就可以在类中使能元对象特性,诸如动态属性,信号,以及槽。一般实际使用中,我们总是把Q_OBJECT宏放置在类声明时的开头位置,除此之外我们的类还需要继承QObject类。
  3. 元对象编译器(Meta-Object Compiler,缩写moc),为每个QObject的子类提供必要的代码去实现元对象特性。我们可以认为Qt对C++进行了一些拓展,moc则是负责将这些拓展语法翻译成原生的C++语法,之后交给C++编译器去编译。

Qt中内存管理机制

主要是通过对象树和智能指针。

对象树

Qt中的对象可以形成一个层次结构,一个对象可以拥有多个子对象。当父对象被销毁时,它会自动销毁其所有子对象。一个对象只能有一个父对象,不然释放就乱套了。

Qt里所有类的最终父类是QObject。ui设计里,QWidget是所有ui组件最大的父对象。QWidget继承于QObject。

在设置父对象时,父对象保存子对象地址,使用容器存储,因为可能有多个,方便管理。父对象析构时会自动析构子对象。

智能指针

Qt智能指针主要有  Qpointer(和普通指针类似,但是所指内容被释放后,自动指null)

QSharedPointer,QWeakPointer和C++的类似,QScopedPointer类似unique_ptr.

Qt窗口对象的父子关系如何指定?有什么作用与好处?

可以初始化时指定父对象,也可以用setParent函数。

子窗口随父窗口显示和隐藏,父窗口销毁也会一起销毁子窗口。

Qt中的事件机制

qt的事件机制基于事件循环,开启事件循环后,监听事件队列。当有事件发生时,Qt的事件系统会捕获并分发这些事件,然后通过事件过滤器、事件处理器或重写虚函数的方式进行处理。事件处理函数会在事件循环中被调用,以响应事件的发生。事件处理器可以处理多种类型的事件,具体的事件类型在函数的参数或者事件对象中提供。事件用于响应外部的、直接触发的操作,例如处理鼠标、键盘、窗口等外部事件。

Windows系统的事件循环由Windows API提供的消息循环机制来实现事件处理,将Windows的消息转换为Qt事件,而Linux系统由epoll多路复用机制完成.

Qt信号与槽机制

qt的信号与槽机制实现对象间的通信,和回调函数很像。信号是由Qt对象自身主动发出的,它表示一种对象状态的变化或特定的动作发生。connect创建一个信号与槽函数的连接,对象发出信号后,通过槽函数来处理信号,并执行相应的操作。不同的对象可以实现松耦合的通信方式。

单线程的信号与槽实现原理主要由观察者模式(一种设计模式)与函数指针的联合使用,槽函数会订阅自己感兴趣的信号,当信号触发时,会通过一个队列获取到函数参数,完成功能的实现。这样实现便可以做到一个信号可以连接多个槽,多个信号也可以连接一个槽。

多线程的信号与槽实现原理本质上是事件机制,信号发送时会触发一个事件,发送到槽函数所在线程的事件队列中,槽函数会排队执行对应的事件函数,完成信号与槽的调用。

Qt信号与槽机制的优缺点

优点

 1.类型安全:需要关联的信号槽的签名必须是等同的。即信号的参数类型和参数个数同接受该信号的槽的参数类型和参数个数相同。若信号和槽签名不一致,则编译器会报错。
 2.松散耦合:信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是哪个对象的那个槽接收它发出的信号,它只需要在适当的时间发送适当的信号即可,而不需要关心是否被接收和哪个对象接收了。Qt保证适当的槽得到了调用,即使关联的对象在运行时删除,程序也不会崩溃。
 3.灵活性:一个信号可以关联多个槽,多个信号也可以关联同一个槽。

缺点

与直接调用回调函数相比,速度慢很多。原因是:

  • 需要定位接收信号的对象。
  • 安全地遍历所有槽。
  • 编组,解组传递参数。
  • 多线程的时候,信号需要排队等候。

观察者模式

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生变化时,会通知所有的观察者对象,使它们能够自动更新自己的状态。

信号与槽的连接方式(connect第五参数)

Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。

Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。

Qt如果一个信号的处理方法一直未被执行,有哪些可能?

1.槽函数所在对象已经被销毁

2.连接断开了(可能是别的地方使用disconnect)

3.槽函数的线程没有开事件循环

4.事件循环阻塞导致消息未发出

5.在连接建立之前就发出信号,等连接建立后已经无法再收到了

Qt中多线程如何在创建子线程时传递参数,子线程在执行过程中如何向其它线程传递执行结果?

如何传递参数:

        在继承QThread或QRunnable的类中重写run()函数实现线程时,可以在此类添加成员变量,在开启线程之前给成员变量赋值,run()函数便可使用该成员变量。

        在使用moveToThread()方法使用线程时,线程的启动是通过信号调用槽开启的,直接通过信号与槽传参。

如何传递执行结果:

        直接通过信号与槽机制传递,不过要求槽函数所在的线程必须开启事件循环。

QPainter 是什么?它用于哪些场景?

QPainter 是 Qt 的绘图引擎,用于绘制各种图形元素和渲染文本。 它提供了很多常用的函数,例如画矩形、画圆等可以绘制基本图形。它还包含设置画笔宽度、颜色和样式、字体,渐变、图案、透明度的功能等,使用户可以使用相对简单的步骤呈现出复杂的效果。

使用 QPainter可以在窗口或其他部件上实现自定义的渲染,并创建自己的图标、图表和数据可视化工具,增强应用程序的用户体验。

Qt 中有哪些类型的定时器?它们之间有何区别

    QTimer:是一个通用的、基于事件的定时器,用于在指定时间间隔后触发 timeOut() 信号。

    QBasicTimer:是用于更高级别的定时操作的辅助类。它允许对象创建一个内部计时器,并使用 timerEvent() 函数处理超时事件。

两者均支持逐个次数触发或重复触发方法,但 QBasicTimer 可自行管理其内部定时器,这使得它更适合于需要细粒度的定时器操作。

QTimer需要自己编写方法,通过timeout信号连接槽(自己编写的方法),达到定时作用
QBasicTimer需要我们重写timerEvent()函数

Qt多线程四种方法

1.继承Qthread,重写run函数

2.继承QObject,调用moveToThread将创建的工作类对象移动到一个线程执行。线程启动和结束有信号可以连接到槽

3.QthreadPool线程池,需要创建工作类继承QRunnable,然后重写run函数,线程池调用start插入任务到线程池,start函数要传入工作类对象的指针

4.QtConcurrent是一个命名空间,提供一些并行计算的API,不用考虑创建线程的问题,调用QtConcurrent::run( func );  使用QFuture接收结果,和c++11的async很像

Qthread介绍

QThread:Qt提供的最基础的线程类,一个对象管理一个线程,自己维护线程启动停止,创建销毁,当然也能基于此类自己建立一个线程池。

一个类通过继承Qthread,重写run函数可以实现多线程,run函数的内容就是工作内容。创建类对象后,调用run函数启动子线程开始工作。

这个继承了Qthread的类一般是在主线程实例化,其成员函数也都是在主线程,只有其成员run函数运行在子线程中,run创建的变量也是属于子线程。

    当需要创建一个独立的线程来执行某个任务,且需要对线程的整个生命周期进行管理时,适合使用 QThread 方式。

    当任务逻辑相对简单或独立,不需要频繁地进行线程间通信时,可以选择使用 QThread 方式。

MoveToThread方法的多线程

一个工作类继承QObject,创建成员函数,可以有多个,执行不同任务。使用指针new一个Qthread, 然后实例化这个工作类的对象,调用moveToThread将对象移动到线程。连接线程的start函数和工作类的几个工作函数,调用start实现多线程工作。

    当需要将一个 QObject 对象移动到指定的线程中执行任务,或者需要多个对象在同一线程中协同工作时,适合使用 moveToThread() 方式。

     当需要灵活地控制对象和线程之间的关系,进行复杂的线程间通信时,可以选择使用 moveToThread() 方式。

QThreadPool线程池

Qt 中使用线程池需要先创建任务,添加到线程池中的每一个任务都需要是一个QRunnable类型,因此在程序中需要创建子类继承QRunnable这个类,然后重写run方法,在这个函数中编写要在线程池中执行的任务,并将这个子类对象传递给线程池,这样任务就可以被线程池中的某个工作的线程处理掉了。

任务类如果使用 Qt 的信号槽机制进行数据的传递就必须同时继承QObject这个类,如果不使用信号槽传递数据就可以只继承QRunnable即可。

QT为应用程序默认提供了一个全局的线程池,通过globalInstance获得其指针。

static QThreadPool * QThreadPool::globalInstance();

QtConcurrent

如果只是普通的任务,没有对象和线程间通信什么乱七八糟的,那QtConcurrent是首选。直接调用

QtConcurrent::run,第一个参数是线程池指针,没有传则默认用全局线程池,之后的可执行对象与参数,可以参考c++11的async,结果使用QFuture接收。

QtConcurrent 提供了一个将任务分发到处理器所有的核的易用接口。线程代码完全被隐藏在 QtConcurrent 框架下,所以你不必考虑细节。不能用于线程运行时需要通信或阻塞的情况。

信号与槽机制原理

  • moc查找头文件中的signals,slots,标记出信号和槽。
  • 将信号、槽信息存储到类静态变量staticMetaObject中,并且按声明顺序进行存放,建立索引。
  • 当发现有connect连接时,将信号、槽的索引信息放到一个map中,彼此配对。
  • 当调用emit时,调用信号函数,并且传递发送信号的对象指针,元对象指针,信号索引,参数列表到activate函数
  • 通过activate函数找到在map中找到所有与信号对应的槽索引
  • 根据槽索引找到槽函数,执行槽函数。

信号与槽机制需要注意的问题

信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中才能够做到有的放矢,避免产生一些错误。下面就介绍一下这方面的情况。

  1. 信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活 性,因此在速度上还是有所损失,当然这种损失相对来说是比较小的,通过在一台 i586- 133 的机器上测试是 10 微秒(运行 Linux),可见这种机制所提供的简洁性、灵活性还是 值得的。但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。
  2. 信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能 产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射 所接收到的同样信号。
  3. 如果一个信号与多个槽相关联的话,那么,当这个信号被发射时,与之相关的槽被 激活的顺序将是随机的,并且我们不能指定该顺序。
  4. 宏定义不能用在 signal 和 slot 的参数中。
  5. 构造函数不能用在 signals 或者 slots 声明区域内。
  6. 函数指针不能作为信号或槽的参数。
  7. 信号与槽不能有缺省参数。
  8. 信号与槽也不能携带模板类参数。

事件循环

一般main函数最后return  a.exec();  这就是进入开启的事件循环。如果不进入事件循环,那函数很快就直接结束了,不会继续等待事件发生并进行分发。(主事件循环)

子线程在run函数中写exec,它会阻止run函数结束,让子线程始终等待事件队列的任务,从而实现利用信号槽进行线程通信。 (子线程的循环)

在一个线程中时间循环只能启动一个

事件循环如何启动

  • 返回值exec() 方法会返回一个整数值,表示对话框的退出状态。通常,返回 QDialog::Accepted 表示用户点击了对话框的“确定”按钮,返回 QDialog::Rejected 表示用户点击了“取消”按钮。

  • 适用场景:适用于需要等待用户对对话框进行操作的情况,通常用于获取用户的选择结果。

  • 非阻塞调用:使用 show() 方法显示对话框时,程序不会阻塞,可以继续执行后续代码。

  • 非模态对话框:通过 show() 方法显示的对话框是非模态的,用户可以在对话框打开的同时继续与其他窗口进行交互。

  • 不返回状态show() 方法不会返回对话框的退出状态,因为它不会阻塞程序的执行。

  • 适用场景:适用于需要在对话框显示的同时允许用户与其他窗口交互的情况,例如工具提示、信息提示等。

通过创建QEventLoop,调用QEventLoop的exec执行事件循环,其通过循环不断地调用QEventLoop::processEvents()来分发事件队列中的事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16710.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人形机器人建模与控制(六) - 行走控制

第六篇:行走控制 1. 引言 腿式机器人在复杂地形中行走的能力使其成为探索、救援和军事等领域的重要研究对象。在本篇博文中,我们将探讨腿式机器人行走周期、行走运动公式、零力矩点(ZMP)和模型预测控制(MPC&#xff…

计算机毕业设计 | SSM汽车租赁系统(附源码)

1, 概述 1.1 课题背景 随着社会的快速发展,计算机的影响是全面且深入的。用户生活水平的不断提高,日常生活中用户对汽车租赁系统方面的要求也在不断提高,需要汽车租赁系统查询的人数更是不断增加,使得汽车租赁系统的…

MaxState 突破长度和参数量限制(sam out)

新增模块 该代码是一个神经网络模块的实现,主要用于处理输入数据并产生输出。具体而言,该代码有两个类:squash和MaxState。 squash函数定义了一个名为squash的操作,用于对输入进行归一化处理。该函数通过计算兴趣胶囊的模长,并根据模长计算一个标量因子。然后,将标量因…

6-3 求二叉树的深度

作者 DS课程组 单位 临沂大学 本题要求实现一个函数,可返回二叉树的深度。 函数接口定义: int Depth(BiTree T);T是二叉树树根指针,函数Depth返回二叉树的深度,若树为空,返回0。 裁判测试程序样例: #in…

电商API接口:供应商价格与主流电商平台价格做比价

品牌在进行采购工作时,将供应商提供的价格与主流电商平台上的公开价格进行比价是一种非常常见的做法,这样做的目的主要是为了保证自身供应商提供的价格具有竞争力和合理性,从而更好地优化采购工作。 以下是过程中的具体步骤及一些注意事项&a…

基于springboot实现周边游平台个人管理系统项目【项目源码+论文说明】

基于springboot实现周边游平台个人管理系统演示 摘要 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以…

2024年上半年信息系统项目管理师下午真题及答案(第一批)

试题一 某项目包含ABCDEFGH共8个活动,各活动的历时、活动逻辑关系如下表所示: 单击下面头像图片领取更多软考独家资料

git忽略文件不生效解决方案

如下面命令报错 请查看(git学习笔记) 问题解释: Git忽略文件不生效可能是因为.gitignore文件中的规则不正确,或者是已经被跟踪的文件导致规则没有效果。 解决方法: 检查.gitignore文件中的规则是否正确。确保没有语…

分布式一致性必备:一文读懂Raft算法

本文作者:小米,一个热爱技术分享的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好!我是小米,一个热爱分享技术的29岁程序员哥哥。今天我们来聊聊分布式系统中的一个重要算法——Raft。这个算法专门用于管理分布式系统中…

DCL(数据控制)

1. 用户管理 1.1 查询用户 select * from mysql.user; 查询结果: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅代表只能够在当前本机访问,是不可以远程访问的。 User代表的是访问该数据库的用户名。在MySQL中需要通过Host和User来唯一标识…

蓝牙Mesh模块组网时无线回程影响速率吗?

随着科技的发展,智能家居、智能办公等场景越来越广泛地应用于我们的生活。其中,蓝牙Mesh组网技术作为一种新型的无线通信技术,受到了越来越多用户的关注。那么,蓝牙Mesh模块在组网时无线回程过程中是否会影响速率呢?本…

Python爬虫实战:利用代理IP获取电商数据

文章目录 1.电商数据介绍2.爬取目标3.代理IP推荐4.准备工作4.1 模块安装4.2 代理IP获取 5.爬虫代码实战5.1分析网页5.1.1 获取cookie5.1.2 关键词分析5.1.3 翻页分析5.1.4 数据获取分析 5.2 发送请求5.3 提取数据5.4 保存数据5.5 完整源码5.6 数据分析六、总结 1.电商数据介绍 …

解决问题的多样手段:不止律师

在我们日常生活和工作中,总是会遇到各种各样的问题。有时我们会不由自主地想到找律师打官司,认为这是解决问题的唯一途径。然而,解决问题其实有很多手段,律师和法庭只是其中的一种。事实上,只要能够发现问题并及时解决…

基于LLM的优化器

基于LLM的优化器 代码输出 需求描述: 我准备用二台8卡的GPU服务器训练一个LLM模型,因为不同的超参会导致不同的性能.我准备了一个脚本,输入一些参数,会运行训练脚本,之后输出tokens/sec,这个值越大越好。 你现在是一个优化器,我告诉你有哪些输入参数,以及它们值的范围,你输出参…

php祛除mqtt 返回数据中包含的特殊字符

function cleanseMessage($message) {// 定义特殊字符的正则表达式$pattern /[[:^print:]]/;// 使用正则表达式替换特殊字符为空字符串$cleanedMessage preg_replace($pattern, , $message);return $cleanedMessage; }// 假设接收到的MQTT消息是: $rawMessage &q…

Spring Boot中@Value加载配置的替代者:@ConfigurationProperties

Value注解Spring Boot开发者都已经熟悉了,通过该注解,我们可以快速的把配置信息加载到Spring的Bean中。 例如:在application.yml中添加了一个配置如下: 我想在service中获取name,通过value注解方式实现,代…

人力资源管理信息化系统如何支持企业开展管理诊断?

华恒智信人力资源顾问有限公司致力于帮助企业开展人力资源管理方面的各项提升改进工作,在长期的咨询工作中,最常听到企业提到的问题莫过于管理诊断方面的问题,事实上,很多企业在日常工作中,都意识到企业内部存在管理方…

比例溢流阀的放大器找BEUEC

液压比例放大器的使用范围广泛,包括工业生产线、船舶液压系统等多个领域。BEUEC比例放大器是一种重要的液压系统组件,其作用是将微弱的液压信号放大,以实现对液压系统的精确控制。这种设备在多个行业中都有广泛的应用,特别是在需要…

C++ List完全指南:使用方法与自定义实现

文章目录 list的使用几种构造函数 list的实现1.节点类的定义1.1节点类的构造函数 2.正向迭代器实现2.1operator*重载2.2operator->重载2.3operator重载2.4operator--2.5operator和operator! 3.反向迭代器实现3.1operator*重载3.2operator->重载3.3operator重载…

ES2020新特性概览

以下是ES2020版本中的一些新特性: Promise.allSettled:Promise.allSettled()方法返回一个在所有给定的promise已被决议或被拒绝后决议的promise,返回的 promise 根据每个 Promise的结果状态决定其决议方式(注意:与Prom…