在QT自定义对象中使默认构造函数为私有

时间:2015-09-15 14:08:05

标签: c++ qt constructor friend access-control

我正在阅读有关自定义类型的this QT文档页面,并说明了以下内容:

  

默认构造函数,复制构造函数和析构函数都是必需的,如果要将类型集成到元对象系统中,则必须是公共的。

假设我有一个需要使用一些必需参数构建的对象,因为没有必要使用默认构造函数构建,例如:

struct IntPair
{    
    IntPair(int first, int second);
    ~IntPair();
};

要使其在QT元对象系统中可用,正如文档所述,它需要默认构造函数。但实际上,没有任何意义可以在没有一对整数的情况下构建一个IntPair对象(对于这个丑陋的例子而言很抱歉)。

有没有办法在不实现默认构造函数的情况下实现这一目的?我正在考虑我的对象和QT元对象系统之间的某种友谊 ......

基本上,我无法理解为什么需要默认构造函数。

4 个答案:

答案 0 :(得分:2)

它与QVariant(模板化)实现有关。

查看QT5.5源代码树中的qvariant.h,你会发现这个:

       T t;
       if (v.convert(vid, &t))
            return t;
       return T();

还有:

       old->~T();
       new (old) T(t); //call the copy constructor

因此需要一个公共构造函数/析构函数和copy-constructor。

所有这一切的优点是能够在信号/插槽(以及其他元对象魔法)中使用您的自定义类型,但是在您的情况下存在缺点。这只是你必须要做的权衡。

作为一种解决方法,你可以使用某种" init()"在构造之后实际初始化对象的方法。不那么安全/优雅,但它有效。

答案 1 :(得分:1)

至于为什么,背后有design个原因。它涉及"Identity vs Value"讨论,我认为这个讨论太长了,无法在此处粘贴。

对于如何,@ AlexanderVX评论了在参数中使用默认值。

答案 2 :(得分:1)

问题有两个部分:

  1. 在不实现默认ctor的情况下实现自定义元对象。
  2. 了解为什么Qt在这种情况下需要默认的ctor。

其他受访者已经回答了(2)。

我想讲(1)。

我写了一个类,我打算让该类的用户调用我写的ctor,它需要几个参数。但是,由于与Qt相关的要求,我被迫添加一个零参数的构造函数。

让我感到高兴的是至少将零参数ctor设为私有,这样我就可以强制所有用户代码 EXCEPT moc生成的“魔术”代码都将被禁止使用该ctor

你好,幸福!有可能。

您确实可以使用友谊将默认的ctor设为私有,并且仍然使用Qt元类型。

它看起来像这样:

class MyClass {
  Q_GADGET

  Q_PROPERTY(QString text READ text)

 public:
  MyClass(QString text, bool sometruth, int someint);

  QString text() const { return text_; }

 private:
  // Works in my project using Qt 5.12. (see hints below if it fails for you)
  friend struct QtMetaTypePrivate::QMetaTypeFunctionHelper<MyClass, true>;
  // Prefer the ctor that takes arguments. This ctor only exists to satisfy Qt.
  MyClass();

  QString text_;
};

有两种方法可以解决弄清要成为朋友的的问题。

您可以将ctor标记为私有,尝试重新编译,并仔细检查编译器错误,以找出其他哪种类型试图访问您的类的ctor。

或者,您可以将assert(false);放在ctor的 body 中,创建带有调试符号(包括Qt调试符号)的二进制文件,然后在调试器中查看堆栈断言失败。堆栈将显示调用ctor的Qt内部成员函数或自由函数。无论来电者是什么朋友。

最后一种方法(使用调试器)对我有用。 (我对流利的编译器语言还不够流利,无法识别出我作为朋友需要添加的巨大编译器错误输出中的哪种类型。)

答案 3 :(得分:0)

自定义数据类型应该具有公共默认构造函数,因为Qt框架的许多部分将调用它以避免返回空指针。例如。 QVariant和容器访问器(例如QHash :: value())。

在你的情况下IntPair():IntPair(0,0){}应该很好,不是吗?

在许多情况下,将数据保存在迫使Qt的隐式共享模式的对象中是很方便的(参见http://doc.qt.io/qt-5/implicit-sharing.html),在这种情况下,默认构造函数可以使用QSharedDataPointer(0)轻松初始化并且每个访问者返回指针为空时的默认值(例如0表示int,QString()表示QString等),猜猜:每个访问者都可以通过调用数据类型的公共默认构造函数来提供默认值,因为它要求有一个:-)。