19

或以其他方式表达我的问题(尽管它没有解决我的问题):'QObject::QObject' 无法访问在类'QObject' 中声明的私有成员

我的班级需要 SIGNAL 和 SLOTS 功能,但我认为如果不从QObject?

class MyClass
{
signals:
   importantSignal();
public slots:
   importantSlot();
};

问题似乎是我需要从中派生QObject以使用信号和插槽......但我需要MyClass. 但由于以下特性,我无法构造它们QObjectNo Copy Constructor or Assignment Operator

我试了很多...

所以我的 shou Class 看起来像这样:

#include <QObject>
class MyClass: public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0); //autogenerated by qtcreator for QObject derived class
    MyClass(const MyClass * other);

signals:
    importantSignal();
public slots:
    importantSlot();
};

我需要MyClass.

那么有没有可能避免“'QObject :: QObject'无法访问在类'QObject'中声明的私有成员”错误?

或者作为替代方案是否有可能使用没有 的信号和插槽QObject

我很高兴有任何建议。

4

6 回答 6

11

If you want a copyable object with QObject features you need membership (by pointer) rather than inheritence.

You can derive a class Handler from QObject where Handler's slots call SomeInterface virtual functions on its parent.

struct NonQObjectHandler {
    virtual ~ NonQObjectHandler () {}
    virtual void receive (int, float) = 0;
};

class Handler : public NonQObjectHandler {
    struct Receiver;
    std :: unique_ptr <Receiver> m_receiver;
    void receive (int, float); // NonQObjectHandler
public:
    Handler ();
    Handler (const Handler &); // This is what you're really after
};

class Handler :: Receiver : public QObject {
Q_OBJECT
private:
    NonQObjectHandler * m_handler;
private slots:
    void receive (int, float); // Calls m_handler's receive
public:
    Receiver (NonQObjectHandler *);
};

Handler :: Handler ()
: m_receiver (new Receiver (this))
{
}

Handler :: Handler (const Handler & old)
: m_receiver (new Receiver (this))
{
    // Copy over any extra state variables also, but
    // Receiver is created anew.
}

Handler :: Receiver :: Receiver (NonQObjectHandler * h)
: m_handler (h)
{
    connect (foo, SIGNAL (bar (int, float)), this, SLOT (receive (int, float)));
}

void Handler :: Receiver :: receive (int i, float f)
{
    m_handler -> receive (i, f);
}
于 2011-09-21T16:08:15.570 回答
7

如果您想使用信号/插槽模式实现事件驱动功能,但不想在 Qt 的范围内工作(即,您想在需要复制构造函数的 STL 容器等内部使用您的类),我建议使用Boost::signal

否则,不,如果不派生,您将不可能做您想要的事情,QObject因为该基类是处理 Qt 运行时信号/插槽功能的东西。

于 2011-09-21T15:44:42.163 回答
2

You cannot use Qt's signal/slot mechanisms without using QObject/Q_OBJECT.

You theoretically could create a dummy QObject and compose it into your class. The dummy would then forward the slot calls to your class. You will probably run in to issues with lifetime management, for the reasons that Liz has described in her comment.

于 2011-09-21T16:05:29.677 回答
2

从 Qt5 开始,您可以连接到任何功能

connect(&timer, &QTimer::finished,
        &instanceOfMyClass, &MyClass::fancyMemberFunction);
于 2017-01-01T20:00:46.717 回答
0

在 Qt5 中,您用于QObject::connect连接:signalslot

/*
   QMetaObject::Connection QObject::connect(
    const QObject *sender,
    const char *signal,
    const char *method,
    Qt::ConnectionType type = Qt::AutoConnection) const;
 */

#include <QApplication>
#include <QDebug>
#include <QLineEdit>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QLineEdit lnedit;

    // connect signal `QLineEdit::textChanged` with slot `lambda function`
    QObject::connect(&lnedit, &QLineEdit::textChanged, [&](){qDebug()<<lnedit.text()<<endl;});

    lnedit.show();
    return app.exec();
}

结果:

在此处输入图像描述

于 2017-12-02T13:02:56.267 回答
0

仅仅因为QObject不可复制并不意味着当您的类被复制或分配等时您必须复制它。具体来说,您需要做的就是将您的类与 QObject 的复制和赋值运算符隔离(因为它们已被删除)。

通常,您会将“可复制的不可复制的 QObject”分解为一个单独的类:

// main.cpp
#include <QObject>
#include <QVariant>

class CopyableQObject : public QObject
{
protected:
   explicit CopyableQObject(QObject* parent = nullptr) : QObject(parent) {}
   CopyableQObject(const CopyableQObject& other) { initFrom(other); }
   CopyableQObject(CopyableQObject&& other)      { initFrom(other); }
   CopyableQObject& operator=(const CopyableQObject& other)
   {
      return initFrom(other), *this;
   }
   CopyableQObject& operator=(CopyableQObject&& other)
   {
      return initFrom(other), *this;
   }
private:
   void initFrom(const CopyableQObject& other)
   {
      setParent(other.parent());
      setObjectName(other.objectName());
   }
   void initFrom(CopyableQObject& other)
   {
      initFrom(const_cast<const CopyableQObject&>(other));
      for (QObject* child : other.children())
         child->setParent( this );
      for (auto& name : other.dynamicPropertyNames())
         setProperty(name, other.property(name));
   }
};

您可以在QObject实例之间复制所需的任何属性。上面复制了父对象名称和对象名称。此外,当从另一个对象移动时,它的子对象被重新设置为父对象,并且动态属性名称也被转移。

现在,CopyableQObject适配器实现了所有允许派生类可复制构造、可复制赋值、可移动构造和可移动赋值的构造函数。

您的类需要做的就是从上面的适配器类派生:

class MyClass : public CopyableQObject
{
   Q_OBJECT
public:
   Q_SIGNAL void signal1();
   Q_SIGNAL void signal2();
};

我们可以测试它是否有效:

int main()
{
   int counter = 0;

   MyClass obj1;
   MyClass obj2;
   Q_SET_OBJECT_NAME(obj1);

   QObject::connect(&obj1, &MyClass::signal1, [&]{ counter += 0x1; });
   QObject::connect(&obj1, &MyClass::signal2, [&]{ counter += 0x10; });
   QObject::connect(&obj2, &MyClass::signal1, [&]{ counter += 0x100; });
   QObject::connect(&obj2, &MyClass::signal2, [&]{ counter += 0x1000; });

   Q_ASSERT(counter == 0);
   emit obj1.signal1();
   emit obj1.signal2();
   Q_ASSERT(counter == 0x11);

   QObject obj3(&obj1);
   Q_ASSERT(obj3.parent() == &obj1);
   const auto name1 = obj1.objectName();

   obj2 = std::move(obj1);

   Q_ASSERT(obj3.parent() == &obj2);
   Q_ASSERT(obj2.objectName() == name1);

   emit obj2.signal1();
   emit obj2.signal2();
   Q_ASSERT(counter == 0x1111);
}

#include "main.moc"

完整的、可编译的示例到此结束。

于 2021-09-24T06:45:07.127 回答