在 Qt 自定义对象中使默认构造函数私有
Making default constructor private in Qt custom object
我正在阅读 this 关于自定义类型的 Qt 文档页面,其中说明如下:
The default constructor, copy constructor and destructor are all required, and must be public, if the type is to be integrated into the meta-object system.
假设我有一个需要使用一些必需参数构建的对象,因为使用默认构造函数构建它没有意义,例如:
struct IntPair
{
IntPair(int first, int second);
~IntPair();
};
如文档所述,要使其在 Qt 元对象系统中可用,它需要默认构造函数。但实际上,在没有一对整数的情况下提供构建 IntPair
对象的机会是没有意义的(抱歉这个丑陋的例子)。
有没有办法在不实现默认构造函数的情况下实现这一点?我正在考虑我的对象和 Qt 元对象系统之间的某种 友谊 ...
基本上,我无法理解为什么需要默认构造函数。
至于为什么,有一个 design reason behind it. It involves a "Identity vs Value" 的讨论我认为太长无法粘贴到这里。
关于如何,@AlexanderVX 评论了在参数中使用默认值。
它与 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
因此需要 public constructor/desctructor 和复制构造函数。
所有这些的优点是能够在 signals/slots(和其他元对象魔术)中使用您的自定义类型,但也有缺点,例如您的情况。这只是您必须忍受的权衡。
作为变通方法,您可以使用某种 "init()" 方法在对象构造后实际对其进行初始化。不像 safe/elegant,但它有效。
自定义数据类型应具有 public 默认构造函数,因为 Qt 框架的许多部分将调用它以避免 returning 空指针。例如。 QVariant 和容器访问器(例如 QHash::value()).
在你的情况下 IntPair() : IntPair(0,0) { } 应该不错,不是吗?
在许多情况下,在实现 Qt 隐式共享模式的对象中保存数据很方便(参见 http://doc.qt.io/qt-5/implicit-sharing.html),在这种情况下,默认构造函数可以很容易地使用 QSharedDataPointer(0) 和每个访问器初始化 return 指针为 null 时的默认值(例如 0 表示 int,QString() 表示 QString 等),猜猜是什么:每个访问器都可以通过调用 public 默认构造函数来提供默认值的数据类型,因为它需要有一个 :-)。
问题分为两部分:
- 在不实现默认 ctor 的情况下实现自定义元对象。
- 了解为什么在这种情况下 Qt 需要默认构造函数。
其他受访者已经解决了 (2)。
我想解决 (1)。
我写了一个 class,我打算让这个 class 的用户调用我写的一个 ctor,它需要几个参数。但是,由于 Qt-related 的要求,我不得不添加一个 zero-argument 构造函数。
至少让 zero-arg ctor 私有化会让我很高兴,这样我就可以强制执行所有用户代码 EXCEPT moc-generated "magic" 代码将被禁止使用该构造函数。
你好,幸福!有可能。
你确实可以使用 friendship 将默认的 ctor 设为私有并且仍然使用 Qt Metatype。
看起来像这样:
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_;
};
有两种方法可以解决什么交朋友的问题。
您可以将构造函数标记为私有,尝试重新编译,并仔细检查编译器错误以找出其他类型试图访问您的 class.
的构造函数
或者,你可以在你的ctor的body中放置一个assert(false);
,创建一个带有调试符号(包括Qt调试符号)的二进制文件,然后查看断言失败时堆栈在调试器中。堆栈将显示调用您的 ctor 的 Qt-internal member-function 或自由函数。不管来电者是谁都是朋友。
最后一种方法(使用调试器)对我有用。 (我的 compiler-ese 不够流利,无法从巨大的编译器错误的输出中辨别出哪种类型是我需要添加的朋友。)
我正在阅读 this 关于自定义类型的 Qt 文档页面,其中说明如下:
The default constructor, copy constructor and destructor are all required, and must be public, if the type is to be integrated into the meta-object system.
假设我有一个需要使用一些必需参数构建的对象,因为使用默认构造函数构建它没有意义,例如:
struct IntPair
{
IntPair(int first, int second);
~IntPair();
};
如文档所述,要使其在 Qt 元对象系统中可用,它需要默认构造函数。但实际上,在没有一对整数的情况下提供构建 IntPair
对象的机会是没有意义的(抱歉这个丑陋的例子)。
有没有办法在不实现默认构造函数的情况下实现这一点?我正在考虑我的对象和 Qt 元对象系统之间的某种 友谊 ...
基本上,我无法理解为什么需要默认构造函数。
至于为什么,有一个 design reason behind it. It involves a "Identity vs Value" 的讨论我认为太长无法粘贴到这里。
关于如何,@AlexanderVX 评论了在参数中使用默认值。
它与 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
因此需要 public constructor/desctructor 和复制构造函数。
所有这些的优点是能够在 signals/slots(和其他元对象魔术)中使用您的自定义类型,但也有缺点,例如您的情况。这只是您必须忍受的权衡。
作为变通方法,您可以使用某种 "init()" 方法在对象构造后实际对其进行初始化。不像 safe/elegant,但它有效。
自定义数据类型应具有 public 默认构造函数,因为 Qt 框架的许多部分将调用它以避免 returning 空指针。例如。 QVariant 和容器访问器(例如 QHash::value()).
在你的情况下 IntPair() : IntPair(0,0) { } 应该不错,不是吗?
在许多情况下,在实现 Qt 隐式共享模式的对象中保存数据很方便(参见 http://doc.qt.io/qt-5/implicit-sharing.html),在这种情况下,默认构造函数可以很容易地使用 QSharedDataPointer(0) 和每个访问器初始化 return 指针为 null 时的默认值(例如 0 表示 int,QString() 表示 QString 等),猜猜是什么:每个访问器都可以通过调用 public 默认构造函数来提供默认值的数据类型,因为它需要有一个 :-)。
问题分为两部分:
- 在不实现默认 ctor 的情况下实现自定义元对象。
- 了解为什么在这种情况下 Qt 需要默认构造函数。
其他受访者已经解决了 (2)。
我想解决 (1)。
我写了一个 class,我打算让这个 class 的用户调用我写的一个 ctor,它需要几个参数。但是,由于 Qt-related 的要求,我不得不添加一个 zero-argument 构造函数。
至少让 zero-arg ctor 私有化会让我很高兴,这样我就可以强制执行所有用户代码 EXCEPT moc-generated "magic" 代码将被禁止使用该构造函数。
你好,幸福!有可能。
你确实可以使用 friendship 将默认的 ctor 设为私有并且仍然使用 Qt Metatype。
看起来像这样:
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_;
};
有两种方法可以解决什么交朋友的问题。
您可以将构造函数标记为私有,尝试重新编译,并仔细检查编译器错误以找出其他类型试图访问您的 class.
的构造函数或者,你可以在你的ctor的body中放置一个assert(false);
,创建一个带有调试符号(包括Qt调试符号)的二进制文件,然后查看断言失败时堆栈在调试器中。堆栈将显示调用您的 ctor 的 Qt-internal member-function 或自由函数。不管来电者是谁都是朋友。
最后一种方法(使用调试器)对我有用。 (我的 compiler-ese 不够流利,无法从巨大的编译器错误的输出中辨别出哪种类型是我需要添加的朋友。)