Qt面试题
1.connect几个类型的区别
Qt::ConnectionType:Qt不同类型connect的详细区别说明与应用
一、介绍
1.Qt::AutoConnection
默认连接类型,如果信号接收方与发送方在同一个线程,则使用Qt::DirectConnection,否则使用Qt::QueuedConnection;连接类型在信号发射时决定。
2.Qt::DirectConnection
信号所连接至的槽函数将会被立即执行,并且是在发射信号的线程;倘若槽函数执行的是耗时操作、信号由UI线程发射,则会阻塞Qt的事件循环,UI会进入无响应状态
3.Qt::QueuedConnection
槽函数将会在接收者的线程被执行,此种连接类型下的信号倘若被多次触发、相应的槽函数会在接收者的线程里被顺次执行相应次数;当使用QueuedConnection时,参数类型必须是Qt基本类型,或者使用qRegisterMetaType() 进行注册了的自定义类型
4.Qt::BlockingQueuedConnection
和Qt::QueuedConnection类似,区别在于发送信号的线程在槽函数执行完毕之前一直处于阻塞状态;收发双方必须不在同一线程,否则会导致死锁
5.Qt::UniqueConnection
可以搭配以上所有连接类型使用,一经设置之后,同一信号与同一槽函数的二次连接将会失败
二、场景
多线程中同一对象的不同槽函数,某个槽函数的执行依赖另一个槽函数的执行结果;可以将前一个槽函数的连接类型设置成DirectConnection,确保调用之后能被立即执行
三、测试
1.声明
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QThread> #include <QPushButton> #include <windows.h> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class ThreadWorker : public QObject { Q_OBJECT public: ThreadWorker(QObject* parent); public slots: void queuedConnect(); void directConnect(); }; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: QVector<QThread*> listThread; QVector<ThreadWorker*> listWorker; Ui::Widget *ui; private slots: void on_butDirect_clicked(); void on_butQueued_clicked(); void on_butAuto_clicked(); signals: void directConnect(); void autoConnect(); void queuedConnect(); }; #endif // WIDGET_H
2.实现
#include "widget.h" #include "ui_widget.h" #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); for(int i = 0 ; i < 3 ; i++) { listThread.append(new QThread(this)); listWorker.append(new ThreadWorker(nullptr)); } connect(this,SIGNAL(directConnect()),listWorker[0],SLOT(directConnect()),Qt::DirectConnection); connect(this,SIGNAL(autoConnect()),listWorker[2],SLOT(directConnect()),Qt::AutoConnection); connect(this,SIGNAL(queuedConnect()),listWorker[1],SLOT(queuedConnect()),Qt::QueuedConnection); connect(this,SIGNAL(directConnect()),listWorker[1],SLOT(directConnect()),Qt::QueuedConnection); for(int i = 0 ; i < 3 ; i++ ) listWorker[i]->moveToThread(listThread[i]); for(auto i : listThread) i->start(); qDebug()<<"The main thread id is "<< QThread::currentThreadId(); } Widget::~Widget() { delete ui; for(auto i : listThread) i->exit(); } void Widget::on_butDirect_clicked() { emit directConnect(); } void Widget::on_butQueued_clicked() { emit queuedConnect(); } void Widget::on_butAuto_clicked() { emit autoConnect(); } ThreadWorker::ThreadWorker(QObject *parent) : QObject(parent) { } void ThreadWorker::queuedConnect() { for(int i = 0 ; i <10 ; i ++) Sleep(100); qDebug()<<"The kid thread id is "<< QThread::currentThreadId(); } void ThreadWorker::directConnect() { for(int i = 0 ; i <10 ; i ++) Sleep(100); qDebug()<<"The kid thread id is "<< QThread::currentThreadId(); }
四、结论
同一对象的不同槽函数可以有不同的连接类型,槽函数在哪个线程被执行由连接类型、信号发射时收发双方是否在一个线程决定
Qt面试题:
1.connect几个类型的区别
2.自绘控件
3.Qt常用线程几种方式,数据竞争,加锁同步等等
4.Model-View-Delegate的理解
5.Qt的插件机制是怎么做的
6.信号槽机制是怎么实现的
7.对Qt事件循环的理解
8.Qt的事件分发是怎么做的
9.QMetaObject::invokeMethod
10.元对象系统,信号槽连接方式,事件分发拦截,继承QWidget样式自绘
11.GraphicsView会问一下,几个坐标系,还有怎么用Gpahicsview绘制一个五角星
12.qt实现发布订阅的设计方法
Qt-Pub-Sub: 基于Qt的发布订阅机制
Quick Event: 基于QT设计的一套控制与界面完全分离的代码模型
Qt实战7.轻量级发布订阅模式 - Qt小罗 - 博客园
13.通过c++11的std::bind及std::function实现类方法回调,模拟Qt实现信号槽
使用 C++11 编写类似 QT 的信号槽
https://github.com/chxuan/cpp-utils/tree/master/Connect
Qt事件
1、事件循环一般用exec()函数开启。QApplicaion::exec()、QMessageBox::exec()都是事件循环。其中前者又被称为主事件循环。
事件循环首先是一个无限“循环”,程序在exec()里面无限循环,能让跟在exec()后面的代码得不到运行机会,直至程序从exec()跳出。从exec()跳出时,事件循环即被终止。QEventLoop::quit()能够终止事件循环。
2、事件循环是可以嵌套的,一层套一层,子层的事件循环执行exec()的时候,父层事件循环就处于中断状态;当子层事件循环跳出exec()后,父层事件循环才能继续循环下去。
Qt的事件处理有5中级别:
1.重写控件的事件处理函数:如重写keyPressEvent(),mousePressEvent()和paintEvent(),这是最常用的事件处理方法,我们已经看到过很多这样的例子了。
2.重写QObject::event(),在事件到达事件处理函数时处理它。在需要改变Tab键的惯用法时这样做。也可以处理那些没有特定事件处理函数的比较少见的事件类型(例如,QEvent::HoverEnter)。我们重写event()时,必须要调用基类的event(),由基类处理我们不需要处理的那些情况。
3.给QObject对象安装事件过滤器:对象用installEventFilter()后,所有达到目标控件的事件都首先到达监视对象的eventFilter()函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。
4.给QApplication安装事件过滤器,如果qApp(唯一的QApplication对象)安装了事件过滤器,程序中所有对象的事件都要送到eventFilter()函数中。这个方法在调试的时候非常有用,在处理非活动状态控件的鼠标事件时这个方法也很常用。
5.继承QApplication,重写notify()。Qt调用QApplication::nofity()来发送事件。重写这个函数是在其他事件过滤器处理事件前得到所有事件的唯一方法。通常事件过滤器是最有用的,因为在同一时间,可以有任意数量的事件过滤器,但是notify()函数只有一个。
许多事件类型,包括鼠标,键盘事件,是能够传播的。如果事件在到达目标对象的途中或者由目标对象处理掉,事件处理的过程会重新开始,不同的是这时的目标对象是原目标对象的父控件。这样从父控件再到父控件,知道有控件处理这个事件或者到达了最顶级的那个控件。
C++面试题:
1. new malloc使用的区别
2. static的用途,区别
3. 智能指针相关的,有哪些,区别是什么
4. 多态的实现机制,虚函数表是怎样的
5. 多态有没有别的实现方案
6. 线程,竞争,同步(更偏向于标准库)
7. C++11都有哪些东西,用的咋样
8. 标准库里的容器常用哪些,区别是什么,实现原理
9. 析构函数、构造函数能不能虚拟的,为什么
10. 右值引用了解多少,怎么用
11. 模板用的怎么样,会不会写
12.C++可能会问智能指针/虚函数/面向对象之类的吧?
13.C++可能会问内存模型,线程安全,高速缓存
14.写个单例模式
15.写个斐波那契数列
int Fib(int n)
{
if (n == 1 || n == 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
16.卷数据结构和算法
(1)编码实现字符串转化为数字,例如“24145”-->24145
(2)单链表逆序
(3)冒泡排序,快速排序
2.C++-选择排序、冒泡排序、插入排序、希尔排序、归并排序、快速排序_诺谦的博客-CSDN博客
https://github.com/huihut/interview
其他:
A
1. null指针调用某个类的方法,会怎样
2. 大小端的是什么意思
3. 结构体、类成员的字节对齐
4. 大小端相关的强制类型转换访问问题
5. 类继承问题,B继承A,B什么都没有新增,能不能互相强制转换
6. 私有成员如何访问,除了friend这些
7. 网络传输,json太臃肿,怎么提速。(猜还是直接内存字节传输,约定大小端这种)
8. 多线程、进程、网络,实际去抽象应该要解决一个什么问题(猜是同步,面试官没说)
9. 提了项目的多进程通信用的管道没用socket,说代理问题,但是面试官比较怀疑会有代理问题
B
1、const、static作用。
2、c++面向对象三大特征及对他们的理解,引出多态实现原理、动态绑定、菱形继承。
3、虚析构的必要性,引出内存泄漏,虚函数和普通成员函数的储存位置,虚函数表、虚函数表指针。
4、malloc、free和new、delete区别,引出malloc申请大内存、malloc申请空间失败怎么办。
5、stl熟悉吗,vector、map、list、hashMap,vector底层,map引出红黑树。优先队列用过吗,使用的场景。无锁队列听说过吗,原理是什么(比较并交换)
6、实现擅长的排序,说出原理(快排、堆排)
7、四种cast,智能指针。static_cast, const_cast, reinterpret_cast, dynamic_cast。
8、tcp和udp区别
9、进程和线程区别。
10、指针和引用作用以及区别。
11、c++11用过哪些特性,auto作为返回值和模板一起怎么用,函数指针能和auto混用吗。
12、boost用过哪些类,thread、asio、signal、bind、function
13、单例、工厂模式、代理、适配器、模板,使用场景。
14、QT信号槽实现机制,QT内存管理,MFC消息机制。
15、进程间通信。会选一个详细问。
16、多线程,锁和信号量,互斥和同步。
17、动态库和静态库的区别。
18、c++一般情况下复制对象,都要考虑深拷贝,比如char *成员要申请空间,并拷贝源对象的内存。假设函数返回的临时对象,不可避免有一次拷贝,但实际临时对象会立刻释放掉,此时直接将管理的资源交给新对象即可,不需要重新申请。可以写拷贝构造函数,也可以借助c++11移动构造函数move。
C
1、统计字符串中出现次数最多的字母并输出
2、上亿行数据的查询 c++
3、C++查找文本中出现最频繁的10个单词
D
1、map和unordered_map区别及其优缺点
map和unordered_map区别及其优缺点 - 己平事 - 博客园
2、map和unordered_map的key可以是什么数据类型?能否是c++类?
C++ map的键类型可以是一个类,比如键类型可以是C++标准库中的string类,
但是对作为键的类有一个约束,那就是这个类必须定义小于操作符,也就是要重载小于运算操作符。
C++标准库的string类就定义了小于操作符。
3、map和multimap的区别
map支持唯一键值,每个键只能出现一次;而multimap中相同键可以出现多次。multimap不支持[]操作符。
4、c++11 share指针,shared_ptr,什么时候引用计数-1?是否一定是内存安全?
当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它。
主动释放对象
shared_ptrr<int> up1(new int(10));
up1 = nullptr ;//int(10) 的引用计数减1,计数归零内存释放
或up1 = NULL; //作用同上
重置
up.reset() ; //将p重置为空指针,所管理对象引用计数 减1
up.reset(p1); //将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控
up.reset(p1,d); //将p重置为p(的值),p 管控的对象计数减1并使用d作为删除器
交换
std::swap(p1,p2); //交换p1 和p2 管理的对象,原对象的引用计数不变
p1.swap(p2); //同上
5、c++11的泛型,有哪些了解?
6、c++联合体,哪些数据类型可以?类行不行?
class Hello
{
Hello()
{
std::cout << "hello" << std::endl;
}
~Hello()
{
}
};
class World
{
World()
{
std::cout << "world" << std::endl;
}
~World()
{
}
};
//共用体(union)是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。
//Union的一大特征在于,一个Union类中的所有数据共享同一段内存。
//如果union类的成员包含自己的构造函数,析构函数,那么同一Union类的成员在初始化时,就有可能会执行不同的构造函数。
//这是无法预料的。所以,我们在定义Union类时要尽量避免成员变量是对象(含有自己的构造函数)
union MyUnion
{
int iA;
double dA;
char cA;
Hello j;
World r;
std::string strChar;
};
7、vector和list的迭代器怎么设计和实现?vector中迭代器的实现
C++四种类型转换
转换类型操作符 作用
const_cast 去掉类型的const或volatile属性
static_cast 无条件转换,静态类型转换
dynamic_cast 有条件转换,动态类型转换,运行时检查类型安全(转换失败返回NULL)
reinterpret_cast 仅重新解释类型,但没有进行二进制的转换
dynamic_cast
//有条件转换,动态类型转换
//1) 安全的基类和子类之间的转换
//2) 必须有虚函数
//3) 相同基类不同子类之间的交叉转换,但结果返回NULL
reinterpret_cast
//仅重新解释类型,但没有进行二进制的转换:
//1) 转换的类型必须是一个指针、应用、算数类型、函数指针或者成员指针
//2) 在比特级别上进行转换,可以把一个指针转换成一个整数,也可以把一个整数
//转换成一个指针,(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,
//还可以得到原先的指针值)。但不能将非32bit的实例转成指针
//3) 最普通的用途就是在函数指针类型之间进行转换。
//4) 很难保证移植性
总结
去const属性用const_cast
基本类型转换用static_cast
多态类之间的类型转换用dynamic_cast
不同类型的指针类型转换用reinterpret_cast
C++单例
单例模式为什么双重校验锁?
双重校验锁第一次进行判空原因:当程序顺序执行的时候,如果不进行判空,每一个线程都会先去获得当前类的类锁,而其他线程都进入阻塞状态。单例模式中初始化单例的程序只会执行一次,大部分情况下会直接到return语句返回,如果都阻塞在获取锁的位置,会大大降低程序的运行速度。
双重校验锁第二次进行判空原因:假设有两个线程A和B,都进行完第一次判空了,A和B都阻塞在此。这个时候A线程获取了类锁,然后B线程被阻塞,A线程新建了一个实例后释放了锁,B线程获取锁,又新建了一个实例,这破坏了单例设计模式的初衷。
#include <iostream>
#include <memory>
#include <mutex>
class Singleton {
public:
static Singleton& GetInstance() {
static std::once_flag s_flag;
std::call_once(s_flag, [&]() {
instance_.reset(new Singleton);
});
return *instance_;
}
~Singleton() = default;
void PrintAddress() const {
std::cout << this << std::endl;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() = default;
private:
static std::unique_ptr<Singleton> instance_;
};
std::unique_ptr<Singleton> Singleton::instance_;
int main() {
Singleton& s1 = Singleton::GetInstance();
s1.PrintAddress();
Singleton& s2 = Singleton::GetInstance();
s2.PrintAddress();
return 0;
}
构造函数能否为虚函数?
构造函数不能是虚函数,因为虚函数是基于对象的,构造函数是用来产生对象的,若构造函数是虚函数,则需要对象来调用,但是此时构造函数没有执行,就没有对象存在,产生矛盾,所以构造函数不能是虚函数。
从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的。问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。
技术分享
1、C++软件异常排查从入门到精通系列汇总
http://t.csdn.cn/7JVfo
2、C++软件异常的常见原因分析与总结(实战经验分享)
http://t.csdn.cn/cq35E
3、排查C++软件异常的常见思路与方法(实战经验总结)
http://t.csdn.cn/VMCz7
4、Visual Studio高效调试手段与技巧总结(经验分享)
http://t.csdn.cn/C00bO
5、分析C++软件异常需要掌握的汇编知识汇总
http://t.csdn.cn/OxTDs
6、Windows和Linux下排查C++软件异常的常用调试器与内存检测工具详细介绍
http://t.csdn.cn/sXDx1
7、内存越界一定会导致程序崩溃吗?详解内存越界
http://t.csdn.cn/mGphU
如何找合适的C++项目给自己的简历加分
https://www.zhihu.com/question/280881677/answer/2604431959
重点关注张小方的回复
更多关于Qt的面试题,请下载资源汇总:
https://download.csdn.net/download/libaineu2004/86338415
————————————————
版权声明:本文为CSDN博主「利白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/libaineu2004/article/details/126173187