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?

- 566
- 2
- 6
- 22
-
Could you provide any situation, when you need to register `QObject`-based class as metatype? Documentation is OK. – Dmitry Sazonov Sep 17 '14 at 12:42
-
You don't need to register QObject or its sub classes with qRegisterMetaType. – vahancho Sep 17 '14 at 12:43
-
`qRegisterMetaType` registers user defined types, not the ones derived from QObject – Rafal Mielniczuk Sep 17 '14 at 12:44
-
@RafalMielniczuk, but why my class must have copy-constructor to work like QObject? I mean storing in QVariant. Any reasons? – VALOD9 Sep 17 '14 at 12:48
3 Answers
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);
-
But why my class must have copy-constructor to work like QObject? I mean storing in QVariant. – VALOD9 Sep 17 '14 at 12:46
-
3Yes, to be stored in `QVariant` your class must have a copy constructor, but it is not "work like QObject", because QObject, QWidget... can't be stored in `QVariant` – Ezee Sep 17 '14 at 12:48
-
-
-
The reason is the same that you can't write `QObject o1 = o2`. It doesn't have state, it can't be serialized, deserialized, copied. It's not a kind of storage. `QThread` is also `QObject`. Could you imagine serializing of a thread?) – Ezee Sep 17 '14 at 13:10
-
So look at `QObject` not as storage but as process, that can't be suspended. – Ezee Sep 17 '14 at 13:16
-
-
1No, you can't. But you can create it with a pointer to QObject. However, if you think of copying QObject, I suggest to you consider moving all variables of you object to a `struct` State and then create `QVariant` with this state, then create a new object with the same state. – Ezee Sep 17 '14 at 18:23
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.

- 8,801
- 1
- 35
- 61
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.

- 1
- 1

- 95,931
- 16
- 151
- 313