Could I have copy constructor for subclass of QObj

2020-02-01 05:39发布

问题:

Here we can read that no copy construct and copy assignment operator evaluable. But here we can read that qRegisterMetaType and Q_DECLARE_METATYPE have to have public default constructor, public copy constructor and public destructor. The question is: who is telling a lie? Or I did not understand it correctly?

回答1:

Everything is true:
1. QObject can't be copied and all its descendants can't be copied also.
2. Q_DECLARE_METATYPE accepts objects with public constructor, copy constructor and destructor.

There is no contradiction, because you can't register QObject descendants with Q_DECLARE_METATYPE.

EDIT:

When you convert your class to QVariant it uses a copy constructor to make a copy of your object:

 void *ptr = QMetaType::construct(x->type, copy);


回答2:

Q_DECLARE_METATYPE macro is used to generate information for custom user types, if you want to use them as SIGNAL/SLOT arguments.

Example:

struct MyInfo
{
  QString name;
  QDate birthday;
};

Q_DECLARE_METATYPE( MyInfo )

// ... somewhere in cpp:
{
  QObject::connect( obj1, SIGNAL( newData( MyInfo ), SLOT( onNewData( MyInfo ) ) );
}

Without Q_DECLARE_METATYPE macro you could not pass MyInfo as signal or slot argument.

If you use cross-thread connections (Qt::QueuedConnection, Qt::BlockingQueuedConnection, etc) you also need to register your type with qRegisterMetatype<MyInfo>(); call.


But it is ok, to use Q_DECLARE_METATYPE to register POINTERS to QObjects. For example:

class MyItem
  : public QObject
{
  Q_OBJECT
//...
};

Q_DECLARE_METATYPE( MyItem * )
// or event better Q_DECLARE_METATYPE( QSharedPointer< MyItem > )

Pointers are POD types, that may be constructed, copied, etc.



回答3:

You can certainly implement a copy constructor and assignment operators in a class that derives from QObject, but you can't refer to the deleted base class copy constructor and assignment operator. You need to roll your own.

Thus, you need to live with the fact that the copy construction or assignment won't affect the signal/slot connections to either the source or the target object. You must also decide how the parentage is handled when copying - either of the three possible choices are entirely arbitrary - that's why it makes no sense to copy objects in most cases, it's too error prone.

For example, using the copy-and-swap idiom.

class CopyableObject : public QObject
{
  Q_OBJECT
public:
  friend void swap(CopyableObject & first, CopyableObject & second) {
    // d_ptr swap doesn't take care of parentage
    QObject * firstParent = first.parent();
    QObject * secondParent = second.parent();
    first.setParent(0);
    second.setParent(0);
    first.d_ptr.swap(second.d_ptr);
    second.setParent(firstParent);
    first.setParent(secondParent);
  }
  CopyableObject(const CopyableObject & other) : QObject(other.parent()) {
    Q_ASSERT(thread() == other.thread());
    setObjectName(other.objectName());
    blockSignals(other.signalsBlocked());
  }
  CopyableObject(QObject * parent = 0) : QObject(parent) {}
  // C++11 only
  #if __cplusplus >= 201103L
  CopyableObject(CopyableObject && other) : CopyableObject() {
    swap(*this, other);
  }
  #endif
  CopyableObject & operator=(CopyableObject other) {
    swap(*this, other);
    return *this;
  }
};

Note that you need to reimplement the swap function for derived classes.