【问题标题】:Could I have copy constructor for subclass of QObject?我可以为 QObject 的子类提供复制构造函数吗?
【发布时间】:2014-09-17 12:39:24
【问题描述】:

Here 我们可以读到没有复制构造和复制赋值运算符可评估。但是here 我们可以读到qRegisterMetaTypeQ_DECLARE_METATYPE 必须具有公共默认构造函数、公共复制构造函数和公共析构函数。问题是:谁在说谎?还是我没有正确理解?

【问题讨论】:

  • 当您需要将基于QObject 的类注册为元类型时,您能提供任何情况吗?文档没问题。
  • 您不需要使用 qRegisterMetaType 注册 QObject 或其子类。
  • qRegisterMetaType 注册用户定义的类型,而不是从 QObject 派生的类型
  • @RafalMielniczuk,但为什么我的班级必须有复制构造函数才能像 QObject 一样工作?我的意思是存储在 QVariant 中。有什么原因吗?

标签: c++ qt copy-constructor moc copy-assignment


【解决方案1】:

一切都是真的:
1.QObject不能被复制,它的所有后代也不能被复制。
2.Q_DECLARE_METATYPE接受具有公共构造函数、复制构造函数和析构函数的对象。

没有矛盾,因为你不能用Q_DECLARE_METATYPE注册QObject的后代。

编辑:

当您将您的类转换为QVariant 时,它会使用复制构造函数来制作您的对象的副本:

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

【讨论】:

  • 但是为什么我的班级必须有复制构造函数才能像 QObject 一样工作?我的意思是存储在 QVariant 中。
  • 是的,要存储在QVariant你的类必须有一个复制构造函数,但它不是“像QObject一样工作”,因为QObject,QWidget...不能存储在@987654328 @
  • 在答案中添加了有关复制构造函数的说明。
  • 你能解释一下为什么我不能将 QObject 存储在 QVariant 中吗?
  • 不,你不能。但是您可以使用指向 QObject 的指针来创建它。但是,如果您考虑复制 QObject,我建议您考虑将对象的所有变量移动到 struct 状态,然后使用此状态创建 QVariant,然后创建具有相同状态的新对象。
【解决方案2】:

Q_DECLARE_METATYPE 宏用于生成自定义用户类型的信息,如果您想将它们用作 SIGNAL/SLOT 参数。

例子:

struct MyInfo
{
  QString name;
  QDate birthday;
};

Q_DECLARE_METATYPE( MyInfo )

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

如果没有Q_DECLARE_METATYPE 宏,您无法将MyInfo 作为信号或槽参数传递。

如果您使用跨线程连接(Qt::QueuedConnectionQt::BlockingQueuedConnection 等),您还需要使用 qRegisterMetatype<MyInfo>(); 调用注册您的类型。


但是没关系,使用Q_DECLARE_METATYPE 将POINTERS 注册到QObjects。例如:

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

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

指针是 POD 类型,可以构造、复制等。

【讨论】:

    【解决方案3】:

    您当然可以在派生自QObject 的类中实现复制构造函数和赋值运算符,但不能引用已删除的基类复制构造函数和赋值运算符。你需要自己动手。

    因此,您需要接受这样一个事实,即复制构造或分配不会影响到源对象或目标对象的信号/插槽连接。您还必须决定在复制时如何处理亲子关系 - 三个可能的选择中的任何一个都是完全任意的 - 这就是为什么在大多数情况下复制对象没有意义,它太容易出错。

    例如,使用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;
      }
    };
    

    请注意,您需要为派生类重新实现swap 函数。

    【讨论】:

      猜你喜欢
      • 2010-12-19
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多