Qt面试题

Qt面试经常问到的问题:信号和槽实现的原理,多线程,网络编程,如何操作数据库,Qt的graphichs。

1、Qt 的优点、缺点

优点:跨平台,几乎支持所有平台,接口简单,文档详细,开发效率高

缺点: Qt 作为一个软件平台,比较庞大、臃肿。

2、Qt 的核心机制

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

       1. QObject类为所有对象提供了一个基类,只要继承此类,那创建出的对象便可以使用元对象系统。在声明类时,将Q_OBJECT宏放置于类的私有区域就可以在类中使能元对象特性,诸如动态属性,信号,以及槽。一般实际使用中,我们总是把Q_OBJECT宏放置在类声明时的开头位置,除此之外我们的类还需要继承QObject类。

       2. 元对象编译器(Meta-Object Compiler,缩写moc),为每个QObject的子类提供必要的代码去实现元对象特性。我们可以认为Qt对C++进行了一些拓展,moc则是负责将这些拓展语法翻译成原生的C++语法,之后交给C++编译器去编译。moc工具读取C++源文件。如果它找到一个或多个包含Q_OBJECT宏的类声明,它会生成另一个C++源文件,其中包含每个类的元对象代码。生成的源文件要么#include到类的源文件中,要么(更常见的情况)编译并链接到类的实现。

       3.属性系统 如同很多编译器厂商提供的编译器一样,Qt也提供了一个精妙的属性系统。然而,作为一个独立于编译器和架构的库,Qt不依赖于诸如__property或[property]这样的非标准的编译器特性。Qt的这套属性系统特性可以用于任何Qt支持的编译器与架构。它基于元对象系统(Meta-Object System),这套系统同时也提供信号与槽机制用于对象间通讯。 以下摘录简要说明了属性与成员变量的区别

        1.成员变量是一个“内”概念,是类的结构构成。属性是一个“外”概念,是类的逻辑意义。

        2.成员变量没有读写权限控制,而属性可以指定为只读或只写,或可读可写。

        3.成员变量不对读出作任何后处理,不对写入作任何预处理,而属性则可以。

        4.public成员变量可以视为一个可读可写、没有任何预处理或后处理的属性。 而private成员变量由于外部不可见,与属性“外”的特性不相符,所以不能视为属性。

3、信号与槽机制原理

        信号与槽 信号与槽用于对象之间的通讯。信号与槽机制是Qt的核心特性,也是与其他框架最大的不同之处。Qt的元对象系统使得信号与槽机制得以实现。 在Qt中,使用了信号与槽机制代替了回调机制。信号将会在特定的事件出现时被发出。Qt的控件预定义了很多信号,当然我们也可以继承这些控件以定义自己的子类,然后添加自己的信号。槽是在响应特定信号时会被调用的方法。Qt的控件存在很多预定义的槽,但通常的做法是继承控件以生成自己的子类,然后添加自己的槽,这样我们就可以自行处理感兴趣的信号

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

4、Qt信号槽机制的优势和不足

优点:类型安全,松散耦合。 

1.类型安全:在信号与槽中的信号的参数个数大于或等于槽的参数个数就可以,但是类型必须一一对应。

2.松散耦合:信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是哪个对象的那个槽接收它发出的信号,它只需要在适当的时间发送适当的信号即可,而不需要关心是否被接收和哪个对象接收了。Qt保证适当的槽得到了调用,即使关联的对象在运行时删除,程序也不会崩溃。

3.灵活性:一个信号可以关联多个槽,多个信号也可以关联同一个槽。

缺点:同回调函数相比,运行速度较慢。

速度较慢:与回调函数相比,信号和槽机制运行速度比直接调用非虚函数慢10倍左右。

原因:1.需要定位接收信号的对象。2.安全地遍历所有槽。3.编组,解组传递参数。4.多线程的时候,信号需要排队等候。(然而,与创建对象的new操作及删除对象的delete操作相比,信号和槽的运行代价只是他们很少的一部分。信号和槽机制导致的这点性能损失,对于实时应用程序是可以忽略的。)

5、Qt信号和槽的本质是什么

回调函数。信号或是传递值,或是传递动作变化;槽函数响应信号或是接收值,或者根据动作变化来做出对应操作。

6、信号与槽与函数指针的比较

回调函数使用函数指针来实现的,如果多个类都关注一个类的动态变化,这样就会需要写出一个比较长的列表来管理这些类之间的关系。稍微在编码方面不那么灵活,稍显冗余。

Qt使用信号与槽来解决这个连接问题,这种方式比较清晰简单一些,一个类只需要清楚自己有几个槽函数有几个信号,然后将信号与槽进行连接,Qt会自己处理函数的调用关系。这样在软件设计角度更加的清晰,灵活,不容易出错。

Qt信号与槽机制降低了Qt对象的耦合度。发信号的对象不需要知道有几个槽函数,也不需要关心是否收到信号,或者谁收到了,谁没收到。同样的槽函数也不需要知道谁是信号的发出者。信号只需要在合适的时机发出即可,降低了对象之间的耦合度。

7、Qt 的事件过滤器

父窗口类通过重写eventFilter方法来监听子控件的相关事件进行处理。 使用这种方式的好处是不需要通过重写控件的方式获取某些事件,对于安装了事件过滤器的对象,他们所有的事件都会经过这个事件过滤器,所以就可以直接在父窗口中进行监测。比如某个窗口中有个QLabel对象,我们想要监听他的鼠标点击事件,那我们就需要继承QLabel类,然后重写mousePressEvent事件,如果有其他类型的控件也需要获取某个事件,那是不是都需要继续控件并重写某个事件了,所以我们通过事件过滤器就可以很方便获取某个对象的某个事件。

专门的事件过滤器类,对特定的对象/特定的事件进行处理。 事件过滤器类只需对当前安装的对象进行处理,无需关心其他操作,且一个事件过滤器类可以被多个对象使用,例如Qt文档中的按键过滤示例,KeyPressEater类中的eventFilter过滤了所有的键盘按下事件,只要安装此事件过滤器的控件,都接收不到键盘按键按下的事件,这种就是对某个通用的事件进行过滤,可以进行多次复用。

给QApplication安装事件过滤器,达到全局事件监听的效果。 在notify方法下发事件的时候,QApplication对象可以拿到第一控制权,对某些事件优先进行处理,比如全局的快捷键操作。

注意点:

事件过滤器可以安装在任何继承QObject的对象上,也可以安装在QApplication对象上(全局事件过滤器);

事件过滤器(eventFilter方法)返回值为true,表示将当前事件进行过滤,不会发送到对象本身;如果返回false,表示对当前事件不做任何处理,会通过event()方法将事件分发给原来的对象。如果不知道怎么处理或者返回什么,那就返回父类的eventFilter方法(类似 return QObject::eventFilter(watched, event));

一个对象可以安装多个事件过滤器(也就是一个对象的事件可以被多个对象进行监控/处理/过滤), 并且最先安装的事件过滤器是最后被调用的,类似于栈的操作,先进后出;

一个事件过滤器可以被多个对象安装,但是如果在事件过滤器(eventFilter方法)中把该对象删除了, 一定要将返回值设为true。否则 Qt会将事件继续分发给这个对象,从而导致程序崩溃。

8、为什么 new QWidget 不需要 delete

        Qt提供了一种机制,能够自动、有效的组织和管理继承自QObject的Qt对象,这种机制就是对象树。 Qt库中的很多类都以QObject作为它们的基类。QObject的对象总是以树状结构组织自己。当我们创建一个QObject对象时,可以指定其父对象(也被称为父控件),新创建的对象将被加入到父对象的子对象(也被称为子控件)列表中。当父对象被析构时,这个列表中的所有子对象会被析构。不但如此,当某个QObject对象被析构时,它会将自己从父对象的列表中删除,以避免父对象被析构时,再次析构自己。        

9、信号与槽的多种用法

一个信号可以和多个槽相连 这时槽的执行顺序和在不在同一个线程上有关,同一线程,槽的执行顺序和声明顺序有关,跨线程时,执行顺序是不确定的。

多个信号可以连接到一个槽 只要任意一个信号发出,这个槽就会被调用。

一个信号可以连接到另外的一个信号 当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。

槽可以被取消链接 这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。想主动取消连接就用disconnect()函数中添加任何实现。

使用Lambda 表达式 在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。 

10、Qt connect 函数的连接方式

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

Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数和信号发送者在同一线程。效果看上去就像是直接在信号发送位置调用了槽函数,效果上看起来像函数调用,同步执行。 emit语句后面的代码将在与信号关联的所有槽函数执行完毕后才被执行。

Qt::QueuedConnection:信号发出后,信号会暂时被放到一个消息队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作。 emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕

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

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

11、事件与信号的区别

使用场合和时机不同 一般情况下,在“使用”窗口部件时,我们经常需要使用信号,并且会遵循信号与槽的机制;而在“实现”窗口部件时,我们就不得不考虑如何处理事件了。举个例子,当使用 QPushButton 时,我们对于它的 clicked()信号往往更为关注,而很少关心促成发射该信号的底层的鼠标或者键盘事件。但是,如果要实现一个类似于 QPushButton 的类,我们就需要编写一定的处理鼠标和键盘事件的代码,而且在必要的时候,仍然需要发射和接收 clicked()信号。

使用的机制和原理不同 事件类似于 Windows 里的消息,它的发出者一般是窗口系统。相对信号和槽机制,它比较“底层”,它同时支持异步和同步的通信机制,一个事件产生时将被放到事件队列 里,然后我们就可以继续执行该事件 “后面”的代码。事件的机制是非阻塞的。 信号和槽机制相对而言比较“高层”,它的发出者一般是对象。从本质上看,它类似于传统的回调机制,是不支持异步调用的。

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

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

信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活 性,因此在速度上还是有所损失,当然这种损失相对来说是比较小的,通过在一台 i586- 133 的机器上测试是 10 微秒(运行 Linux),可见这种机制所提供的简洁性、灵活性还是值得的。但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。

信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样信号。

如果一个信号与多个槽相关联的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的,并且我们不能指定该顺序。

宏定义不能用在 signal 和 slot 的参数中。

构造函数不能用在 signals 或者 slots 声明区域内。

函数指针不能作为信号或槽的参数。

信号与槽不能有缺省参数。

信号与槽也不能携带模板类参数。

13、信号的注意点

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

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

所有的信号都不需要定义。

必须直接或间接继承自QOBject类,并且开头私有声明包含Q_OBJECT。

在同一个线程中,当一个信号被emit发出时,会立即执行其槽函数,等槽函数执行完毕后,才会执行emit后面的代码,如果一个信号链接了多个槽,那么会等所有的槽函数执行完毕后才执行后面的代码,槽函数的执行顺序是按照它们链接时的顺序执行的。不同线程中(即跨线程时),槽函数的执行顺序是随机的。

在链接信号和槽时,可以设置链接方式为:在发出信号后,不需要等待槽函数执行完,而是直接执行后面的代码,是通过connect的第5个参数。

信号与槽机制要求信号和槽的参数一致,所谓一致,是参数类型一致。如果不一致,允许的情况是,信号的参数可以比槽函数的参数多,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少),但是不能说信号根本没有这个数据,你就要在槽函数中使用(就是槽函数的参数比信号的多,这是不允许的)。

14、Qt 实现多线程

QtConcurrent运行一个线程池,它是一个更高级别的API,不适合运行大量的阻塞操作:如果你做了很多阻塞操作,你很快就会耗尽池并让其他请求排队.在那种情况下,QThread(较低级别的构造)可能更适合于操作(每个代表一个线程).

15、描述Qt中的文件流(QTextStream)和数据流(QDataStream)的区别

        文件流(QTextStream):操作轻量级数据(int,double,QString)数据写入文本件中以后以文本的方式呈现。 

        数据流(QDataStream):通过数据流可以操作各种数据类型,包括对象,存储到文件中数据为二进制。

        文件流,数据流都可以操作磁盘文件,也可以操作内存数据。通过流对象可以将对象打包到内存,进行数据的传输。

16、Qt 保证多线程安全

互斥量(QMutex) QMutex m_Mutex; m_Mutex.lock(); m_Mutex.unlock();

互斥锁(QMutexLocker) QMutexLocker mutexLocker(&m_Mutex);

从声明处开始(在构造函数中加锁),出了作用域自动解锁(在析构函数中解锁)。等待条件(QWaitCondition)QWaitCondtion m_WaitCondition; m_WaitConditon.wait(&m_muxtex, time);
m_WaitCondition.wakeAll();QReadWriteLock类 》一个线程试图对一个加了读锁的互斥量进行上读锁,允许; 》一个线程试图对一个加了读锁的互斥量进行上写锁,阻塞; 》一个线程试图对一个加了写锁的互斥量进行上读锁,阻塞;、 》一个线程试图对一个加了写锁的互斥量进行上写锁,阻塞。

读写锁比较适用的情况是:需要多次对共享的数据进行读操作的阅读线程。 QReadWriterLock 与QMutex相似,除了它对 "read","write"访问进行区别对待。它使得多个读者可以同时访问数据。使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。

信号量QSemaphore 但是还有些互斥量(资源)的数量并不止一个,比如一个电脑安装了2个打印机,我已经申请了一个,但是我不能霸占这两个,你来访问的时候如果发现还有空闲的仍然可以申请到的。于是这个互斥量可以分为两部分,已使用和未使用。

QReadLocker便利类和QWriteLocker便利类对QReadWriteLock进行加解锁。

17、详解Qt中的内存管理机制

所有继承自QOBJECT类的类,如果在new的时候指定了父亲,那么它在清理时在父亲被delete的时候delete的,所以如果一个程序中,所有的QOBJECT类都指定了父亲,那么他们是会一级级的在最上面的父亲清理时被清理,而不用自己清理;

程序通常最上层会有一个根的QOBJECT,就是放在setCentralWidget()中的那个QOBJECT,这个QOBJECT在 new的时候不必指定它的父亲,因为这个语句将设定它的父亲为总的QAPPLICATION,当整个QAPPLICATION没有时它就自动清理,所以也无需清理。这里QT4和QT3有不同,QT3中用的是setmainwidget函数,但是这个函数不作为里面QOBJECT的父亲,所以QT3中这个顶层的QOBJECT要自行销毁)。

这是有人可能会问那如果我自行delete掉这些Qt接管负责销毁的指针了会出现什么情况呢,如果时这样的话,正常情况下Qt的拥有这个对象的那个父亲会知道这件事情,它会直到它的儿子被你直接delete了,这样它会将这个儿子移出它的列表,并且重新构建显示内容,但是直接这样做是有风险的!

当一个QOBJECT正在接受事件队列时如果中途被你delete掉了,就是出现问题了,所以Qt中建议家不要直接delete掉一个 QOBJECT,如果一定要这样做,要使用QOBJECT的deleteLater()函数,它会让所有事件都发送完一切处理好后马上清除这片内存,而且就算调用多次的deletelater也不会有问题。

Qt不建议在一个QOBJECT 的父亲的范围之外持有对这个QOBJECT的指针,因为如果这样外面的指针很可能不会察觉这个QOBJECT被释放,会出现错误,如果一定要这样,就要记住你在哪这样做了,然后抓住那个被你违规使用的QOBJECT的destroyed()信号,当它没有时赶快置零你的外部指针。当然我认为这样做是极其麻烦也不符合高效率编程规范的,所以如果要这样在外部持有QOBJECT的指针,建议使用引用或者用智能指针,如Qt就提供了智能指针针对这些情况。

Qt中的智能指针封装为QPointer类,所有QOBJECT的子类都可以用这个智能指针来包装,很多用法与普通指针一样,可以详见Qt assistant 通过调查这个Qt的内存管理功能,发现了很多东西,现在觉得虽然这个Qt弄的有点小复杂,但是使用起来还是很方便的,要说的是某些内存泄露的检测工具会认为Qt的程序因为这种方式存在内存泄露,发现时大可不必理会。 

18.描述QT的TCP通讯流程

服务端:(QTcpServer)

①创建QTcpServer对象

②监听listen需要的参数是地址和端口号

③当有新的客户端连接成功回发送newConnect信号

④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连QTcpSocket对象

⑤连接QTcpSocket对象的readyRead信号

⑥在readyRead信号的槽函数使用read接收数据

⑦调用write成员函数发送数据

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer;
    tcpServer->listen(QHostAddress("192.168.0.111"),1234);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(new_connect()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::new_connect()
{
    qDebug("--new connect--");
    QTcpSocket* tcpSocket = tcpServer->nextPendingConnection();
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
    socketArr.push_back(tcpSocket);

}

void Widget::read_data()
{
    for(int i=0; i<socketArr.size(); i++)
    {
        if(socketArr[i]->bytesAvailable())
        {
            char buf[256] = {};
            socketArr[i]->read(buf,sizeof(buf));
            qDebug("---read:%s---",buf);
        }
    }
}

客户端:(QTcpSocket)

①创建QTcpSocket对象

②当对象与Server连接成功时会发送connected 信号

③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号

④connected信号的槽函数开启发送数据

⑤使用write发送数据,read接收数据

Widget::Widget(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

    tcpSocket = new QTcpSocket;

    connect(tcpSocket,SIGNAL(connected()),this,SLOT(connect_success()));

    tcpSocket->connectToHost("172.20.10.3",1234);

}



Widget::~Widget()

{

    delete ui;

}



void Widget::on_send_clicked()

{

    std::string msg = ui->msg->text().toStdString();

    int ret = tcpSocket->write(msg.c_str(),msg.size()+1);

    qDebug("--send:%d--",ret);

}



void Widget::connect_success()

{

    ui->send->setEnabled(true);

}

19.描述UDP 之 UdpSocket通讯

           UDP(User Datagram Protocol即用户数据报协议)是一个轻量级的,不可靠的,面向数据报的无连接协议。在网络质量令人十分不满意的环境下,UDP协议数据包丢失严重。由于UDP的特性:它不属于连接型协议,因而具有资源消耗小处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。所以QQ这种对保密要求并不太高的聊天程序就是使用的UDP协议。

        在Qt中提供了QUdpSocket 类来进行UDP数据报(datagrams)的发送和接收。Socket简单地说,就是一个IP地址加一个port端口  。

流程

①创建QUdpSocket套接字对象

②如果需要接收数据,必须绑定端口

③发送数据用writeDatagram,接收数据用 readDatagram 。

20.多线程使用方法

方法一:①创建一个类从QThread类派生②在子线程类中重写 run 函数, 将处理操作写入该函数中 ③在主线程中创建子线程对象, 启动子线程, 调用start()函数

方法二:①将业务处理抽象成一个业务类, 在该类中创建一个业务处理函数②在主线程中创建一QThread类对象 ③在主线程中创建一个业务类对象 ④将业务类对象移动到子线程中 ⑤在主线程中启动子线程 ⑥通过信号槽的方式, 执行业务类中的业务处理函数

多线程使用注意事项: 
1. 业务对象, 构造的时候不能指定父对象 
2. 子线程中不能处理ui窗口(ui相关的类) 
3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口

21.多线程下,信号槽分别在什么线程中执行,如何控制

可以通过connect的第五个参数进行控制信号槽执行时所在的线程,connect有几种连接方式,直接连接和队列连接、自动连接

直接连接(Qt::DirectConnection):信号槽在信号发出者所在的线程中执行

队列连接 (Qt::QueuedConnection):信号在信号发出者所在的线程中执行,槽函数在信号接收者所在的线程中执行

自动连接  (Qt::AutoConnection):多线程时为队列连接函数,单线程时为直接连接函数。

22.Qt的D指针(d_ptr)与Q指针(q_ptr

D指针

PIMPL模式,指向一个包含所有数据的私有数据结构体。

  • 私有的结构体可以随意改变,而不需要重新编译整个工程项目
  • 隐藏实现细节
  • 头文件中没有任何实现细节,可以作为API使用
  • 原本在头文件的实现部分转移到了源文件,所以编译速度有所提高

Q指针

私有的结构体中储存一个指向公有类的Q指针。

总结

  • Qt中的一个类常用一个PrivateXXX类来处理内部逻辑,使得内部逻辑与外部接口分开,这个PrivateXXX对象通过D指针来访问;在PrivateXXX中有需要引用Owner的内容,通过Q指针来访问。
  • 由于D和Q指针是从基类继承下来的,子类中由于继承导致类型发生变化,需要通过static_cast类型转化,所以DPTR()QPTR()宏定义实现了转换。

23. Qt智能指针相关

Qt的智能指针包括:

  • QSharedPointer
  • QScopedPointer
  • QScopedArrayPointer
  • QWeakPointer
  • QPointer
  • QSharedDataPointer

QSharedPointer

相当于std::shared_ptr,内部维持着对拥有的内存资源的引用计数,引用计数下降到0时,这个内存资源就被释放了。

QSharedPointer是线程安全的,多个线程同时修改QSharedPointer对象也不需要加锁,但是QSharedPointer指向的内存区域不一定是线程安全的,所以多个线程同时修改QSharedPointer指向的数据时还要考虑加锁。

QWeakPointer

类似于std::weak_ptr

QScopedPointer

相当于std::unique_ptr,内存数据只在一处被使用。

QScopedArrayPointer

类似于QScopedPointer,用于指向的内存数据是一个数组时的场景。

QPointer

QPointer只能用于指向QObject及派生类的对象。当一个QObject或派生类对象被删除后,QPointer能自动将其内部的指针设置为0,这样在使用QPointer之前就可以判断一下是否有效了。

QPointer对象超出作用域时,并不会删除它指向的内存对象。

QSharedPointer

用于实现数据的隐式共享。Qt中大量使用了隐式共享与写时拷贝技术,例如:

QString str1 = "abc";

QString str2 = str1;

str2[2] = "X"; 

第二行执行完后,str2和str1指向同一片内存数据。第三行执行时,Qt会为str2的内部数据重新分配内存。这样做的好处是可以有效地减少大片数据拷贝的次数,提高程序的运行效率。

Qt中隐式共享和写时拷贝就是利用QSharedDataPointer和QSharedData这两个类实现的。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在Qt面试中,coding环节通常是测试应聘者Qt编程技能和经验的重要部分。对于Qt面试的coding部分,可能会涉及以下几个方面: 1. Qt基础知识:应聘者需要掌握Qt的基本概念和常用类,了解Qt的对象模型和信号槽机制。可能会出现一些关于Qt类的使用和常见操作的题。 2. UI设计与开发:这部分可能会要求应聘者根据一些需求或UI设计稿实现一个界面。应聘者需要使用Qt的UI设计工具,例如Qt Designer,完成界面的设计和布局,并用C++代码实现界面的功能。 3. 数据处理与算法:有时候面试官会出一些与数据处理或算法有关的题,以考察应聘者对Qt的灵活运用能力。例如,要求实现一个基于Qt的文本编辑器,或者对一组数据进行排序等。 4. 多线程编程:对于需要处理并发或耗时操作的题,可能会考察应聘者的多线程编程能力。这包括使用Qt提供的多线程类或库函数,以及保证线程安全性和避免资源竞争的经验。 5. 调试与题解决能力:面试过程中可能会有意设置一些错误或题,观察应聘者的调试和解决题的能力。应聘者需要能够熟练使用Qt的调试工具,查找和修复代码中的题和错误。 在Qt面试的coding环节中,关键是熟练掌握Qt的基本特性和常用类,以及对数据处理、UI设计、多线程和题解决的经验和能力。同时,良好的编码风格和规范也是考察的一项重点。通过练习和实际项目的积累,不断提升自己的Qt编程技能,才能在Qt面试中有较好的表现。 ### 回答2: QT面试coding主要是针对QT编程技能的考察。在QT面试coding过程中,通常会给出一些编程题或者需要完成一些编程任务。 首先,面试官可能会一些基础的QT题,例如QT的信号与槽机制、布局管理器、窗口部件等等。回答这些题需要我们对QT的相关概念有一定的了解和掌握。 其次,面试官可能会给出一些具体的编程题,要求我们使用QT进行解答。这些题可能涉及到QT的各种功能和模块,例如窗口的绘制、界面的响应事件、文件的读写等。在解答这些题时,我们需要灵活运用QT的相关函数和类进行编程实现。 最后,面试官可能会要求我们完成一些编程任务,例如实现一个简单的QT应用程序、设计一个界面等等。在这些任务中,我们需要运用QT的各种功能和UI设计技巧来完成。 总的来说,QT面试coding主要考察我们对QT编程的熟练程度和实际应用能力。我们需要熟悉QT的相关知识,并能够灵活运用QT进行编程。通过在面试中展示我们的编程能力,我们能够更好地展现自己的优势,提高获得工作机会的几率。 ### 回答3: 在qt面试的coding环节中,通常会要求应聘者完成一个具体的编程任务来评估其在qt开发方面的能力。 首先,面试官可能会询应聘者是否有qt编程经验以及相关项目经验。这些题旨在了解应聘者是否熟悉qt框架,是否能够独立开发qt应用程序,并根据具体需求进行调试和优化。 接下来,面试官可能会给应聘者一个具体的编程题,要求应聘者使用qt编写代码解决该题。这个题可能涉及到窗口和控件的创建、布局、信号与槽的连接、界面交互等方面。 在解决题的过程中,应聘者需要熟悉qt的基本概念和常用的类,比如QWidget、QBoxLayout、QPushButton、QLineEdit等。同时,还需要掌握qt的常用功能,比如事件处理、界面设计和绘图等。 应聘者需要根据题的要求编写代码,并确保代码的可读性、可维护性和效率。在编程过程中,应聘者需要熟练运用qt的API,同时遵循良好的编码规范,确保代码的质量。 此外,应聘者还可以采取一些额外的措施来提高代码的质量和可扩展性,比如使用设计模式、封装可复用的代码、添加注释和文档等。 最后,面试官可能会与应聘者讨论和评价其代码的质量和实现细节。这个过程中,应聘者需要清楚地解释和展示自己的代码实现,并回答面试官的题和疑。 在qt面试的coding环节中,关键是理解题、熟练使用qt的API和功能,并能够用清晰、简洁、高效的代码解决题。同时,代码的可读性和可维护性也是重要的考察因素。通过合理的思考和实现,展示自己在qt开发方面的能力和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值