“QObject”是“Recorder”的一个不明确的基类。

4

我正在尝试在我的新创建的类中使用继承自QObject的QTimer。无论我如何尝试,都会出现错误'QObject' is an ambiguous base of 'Recorder'。我尽力避免在我的简单程序中出现歧义,但仍然陷入了困境。以下是我的类结构。

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;    
    w.show();

    return a.exec();
}

dialog.h:主窗口界面

#ifndef DIALOG_H
#define DIALOG_H

#include "detector.h"
#include <QDialog>
#include <QtCore>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    Detector myDetector;

detector.h: 检测器窗口用户界面

#ifndef DETECTOR_H
#define DETECTOR_H

#include <QDialog>
#include <QtCore>
#include <QObject>
#include "actualrec.h"

namespace Ui {
class Detector;
}

class Detector : public QDialog
{
    Q_OBJECT

public:
    explicit Detector(QWidget *parent = 0);
    ~Detector();
    void run();

private:
    ActualRec theDetector;
    Ui::Detector *ui;

actualrec.h:探测器代码

#ifndef ACTUALREC_H
#define ACTUALREC_H

#include <QtCore>
#include <QObject>    
#include <QImage>
#include "recorder.h"

class ActualRec : public QThread
{
public:
    ActualRec();
    void run();

private:        
    Recorder theRecorder;

recorder.h: 这是录音器的代码,我想在其中使用我的QTimer。

#ifndef RECORDER_H
#define RECORDER_H

#include <QtCore>

class Recorder : public QThread, public QObject
{

public:
    Recorder();
    void run();

private:
    QTimer* theTimer;

recorder.cpp的构造函数有

 *theTimer = new QTimer(this);

输出如下: http://i.imgur.com/Awb6qhd.png 非常感谢您的帮助。

3
QThread 已经是 QObject,无需重复继承。 - vahancho
@vahancho 我确实考虑过这个问题,但是当我不包含公共QObject时,就会出现错误no match for 'operator=' (operand types are 'QTimer' and 'QTimer*') *theTimer = new QTimer(this); ^ - isADon
最终我也会在构造函数中省略*,因为theTimer已经是一个指针了。虽然这样做不能解决问题,但仍然是错误的。顺便提一下,请以文本形式提供错误信息,不要添加图像作为信息。图片链接很快就会失效,所以请更新您的问题。 - Sebastian Lange
@isADon,因为你应该写成theTimer = new QTimer(this);。去掉星号即可。 - vahancho
http://qt-project.org/wiki/Threads_Events_QObjects - BЈовић
你需要计时器做什么?如果你想定期在线程中记录东西并唤醒它,你可以在QWaitCondition上使用定时等待。此外,在停止线程时,您可以通知等待条件以使其提前唤醒。由于等待时间永远不会非常准确(QTimer也是如此),为了使等待时间更加平滑,使用QElapsedTimer来测量时间进度并相应地调整等待计时器。 - Pete
3个回答

3
您的代码存在以下几个问题:
1)Qt线程使用错误。
class Recorder : public QThread, public QObject

a) 因为QThread继承自QObject,所以只需继承QThread而无需显式地继承QObject。

b) 即使您这样做,在一般情况下,历史上应该是列表中的第一个基础。

c) 但是,您可能需要重新考虑如何使用线程。这是一种方式,但不一定是最好的。

2) 在堆上分配QTimer对象

为什么首先要在堆上分配计时器的内存?可以在栈上分配它,特别是因为它是成员变量。那样,您也不需要处理“this”麻烦。整个内存管理变得更加简单。

3) 不使用Q_NULLPTR

对于父项的默认值,应使用Q_NULLPTR而不是0。

4) 包含整个QtCore模块

#include <QtCore>

您应该只包括最终使用的部分。这是一种暴力包含事物的方式。
因此,应该像这样编写:
class Recorder : public QThread
{

public:
    Recorder();
    void run();

private:
    QTimer theTimer;

当然,如果您在Qt中将线程机制用于另一种方式,那么按照继承的方式编写以下代码也是完全可以的:
class Recorder : public QObject

但无论如何,你的代码现在需要作出一些其他的改变,所以代码已经失效了。

感谢您提供详细的答案。我应该如何在构造函数中初始化我的QTimer? - isADon
@isADon:鉴于您之前使用的构造函数参数,没有必要初始化它。这是自动完成的。只需开始使用它即可。确保将其用作“theTimer.”而不是“theTimer->”。 - László Papp
如果您没有建议继承QThread,我会点赞的。请阅读此链接:http://qt-project.org/wiki/Threads_Events_QObjects - BЈовић
1
@BЈовић:你的知识已经过时了(约1.5年)。请更新它:http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html。这是最近核心Qt开发人员之一说的,不是很多年前写过Qt但现在甚至不再从事Qt工作的人。 ;) - László Papp
@FinalContest 谢谢,这个解决方案让我成功编译了代码,没有出现任何错误。但是当我将theTimer连接到我的私有槽setFalse()时,像这样:connect(&theTimer, SIGNAL(timeout()), this, SLOT(setFalse())); 我会得到一个错误 QObject::connect: No such slot QThread::setFalse() 这很有道理,因为我的setFalse在Recorder::setFalse()中而不是QThread中。为什么它会从qThread中调用它呢? - isADon
我能够自己修复它。由于某种原因,.pro文件中缺少一个头文件。 - isADon

3

QThread已经继承自QObject,而且你不能同时从两个继承自QObject的类中继承。


1
你不应该重复继承QObject。这是因为信号和槽通过整数进行映射,而ID可能会发生冲突。
任何从QObject继承的对象都适用于此规则。
class BadClass : public QTimer, public Dialog
{
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接