在Qt中注册元类型的模式

时间:2013-11-21 07:59:01

标签: c++ qt

简介

我有一个库,它注册了一堆元类型,如下代码所示:


abstractfoobase.h

namespace foo {
    enum FooState { OK, MAYBE };
    class AbstractFooBase : public QObject {...};
}

Q_DECLARE_METATYPE(foo::FooState)

还有一个对应的 abstractfoobase.cpp ,内容取决于在基类中实现的内容。


foousingclass.h:

namespace foo {

    class FooUsingClass : public AbstractFooBase {...};
}

还有相应的 foousingclass.cpp ,它有方法实现等。


现在,Q_DECLARE_METATYPE启用了Qt模板类和QVariant的类型。要启用排队信号中的类型等,还需要进行相应的调用:

qRegisterMetaType<foo::FooState>();

问题

qRegisterMetaType来电的好地方是什么?我显然不希望从应用程序代码中进行任何明显的初始化调用。注册必须在执行foo::FooUsingClass *f = new foo::FooUsingClass();之后发生。

在Java中,我将这种代码放在静态初始化块中。我也可以在C ++中看到几种方法来实现这一点,但是它们中没有一个看起来特别好看。例如,简单地将这些放到AbstractFooBase构造函数中将导致每次创建子类实例时都会调用注册,这可能是不希望的开销。所以那些做过这个的人,你在哪里放了qRegisterMetaType电话?

4 个答案:

答案 0 :(得分:6)

我可以想象如下:

in abstractfoobase.cpp:

namespace foo {

/// Initializer
class FooStateInit {
public:
    FooStateInit() {
        qRegisterMetaType<foo::FooState>();
    }
};
static FooStateInit fooStateInit;

} // namespace foo

答案 1 :(得分:5)

我最近发现了一个简单的解决方案,它也适用于静态库。

它充分利用了在Qt的元类型系统中使用qMetaTypeId<>()的事实。因此,通过显式模板实例化,我们可以强制实现与 abstractfoobase.cpp 的链接(否则链接器可能决定是否没有引用的符号)并确保在程序启动时静态注册该类型:

abstractfoobase.h

#include <QMetaType>

namespace foo {
    enum FooState { OK, MAYBE };
}

Q_DECLARE_METATYPE(foo::FooState)

extern template int qMetaTypeId<foo::FooState>();

abstractfoobase.cpp

static const int kFooStateMetaTypeId = qRegisterMetaType<foo::FooState>();

template int qMetaTypeId<foo::FooState>();

答案 2 :(得分:1)

在我创建的几个应用程序中,我曾经只是在main()中注册它们 - 就像定义应用程序启动的函数一样。当然,这将注册与.cpp / .h文件分开,但反过来它保证我不会陷入某些名称冲突(我在一个地方看到所有名称/类型)并且还保证注册完成恰好一次:app startup;)

但是,这不是......'方便'的方式......如果有人有更好的方法,我也希望看到它。

答案 3 :(得分:1)

如果您的类型将被频繁实例化,则可以在构造函数中使用函数静态初始化:

var file = model.UserAvatarImage as IFormFile;
string fileContent = null;
using (var reader = new StreamReader (file.OpenReadStream ())) {
       fileContent = reader.ReadToEnd ();
}
var result = JsonConvert.DeserializeObject<IFormFile> (fileContent); 

优点:

  • 惰性注册-仅在您的类型完全实例化的情况下才会调用
  • 单次注册-不管实例化实例的频率如何,都只会被调用一次。

缺点:

  • 使可执行文件更大