19

または、質問を定式化する他の方法(問題は解決しませんでしたが):'QObject :: QObject'は、クラス'QObject'で宣言されたプライベートメンバーにアクセスできません

クラスにSIGNALsとSLOTSの機能が必要ですが、QObject?から派生しないと不可能だと思います。

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

問題は、信号とスロットを使用するために派生する必要があることのようQObjectです...しかし、デフォルトのコンストラクターが必要ですMyClass。しかし、次の機能のためにそれらを構築できませんQObjectコピーコンストラクターまたは代入演算子がありません。

たくさんやってみました...

だから私のshoulクラスはそのように見えます:

#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

機能を備えたコピー可能なオブジェクトQObjectが必要な場合は、継承ではなく(ポインターによる)メンバーシップが必要です。

のスロットがその親の仮想関数を呼び出す場所Handlerからクラスを派生させることができます。QObjectHandlerSomeInterface

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

QObject/を使用せずにQtの信号/スロットメカニズムを使用することはできませんQ_OBJECT

理論的には、ダミーのQObjectを作成し、それをクラスに構成することができます。次に、ダミーはスロット呼び出しをクラスに転送します。リズが彼女のコメントで説明した理由のために、あなたはおそらく生涯管理の問題に遭遇するでしょう。

于 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 に答える