qvariant是如何和稀泥的

Posted 论睡不着与不想睡的区别

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了qvariant是如何和稀泥的相关的知识,希望对你有一定的参考价值。

unionData



    char c;

    uchar uc;

    short s;

    signedchar sc;

    ushort us;

    int i;

    uint u;

    long l;

    ulong ul;

    bool b;

    double d;

    float f;

    qreal real;

    qlonglong ll;

    qulonglong ull;

    QObject *o;

    void *ptr;

    PrivateShared*shared;

;

QVariant介绍(来自Qt助手)

The QVariant class acts like a union for the most common Qt datatypes.

Because C++forbids unions from including types that have non-default constructors ordestructors, most interesting Qt classes cannot be used in unions. Without QVariant, this would be a problem for QObject::property() and for database work, etc.

QVariant类像是一个大部分Qt基础数据类型的联合体。由于C++的union类型不能包含无默认构造函数或析构函数的成员,导致大部分有用的Qt类不能放到union中。如果没有QVariant,QObject::property、数据库操作等将很难实现。

注:C++ union参考《C++ Primer 第五版》19.6节

 

问题

其实C++ 11已经可以将含有构造函数的复杂类型放入union中,在《C++ Primer 第五版》19.6节有使用类管理这种资源的例子。即使这样,QVariant仍然不能直接将所有需要管理的类型直接以放入union中,因为QVariant管理的Qt数据类型很多,而且未来也会扩展,已存在的类型也有可能扩展,这样QVariant占用的内存至少是它管理的最大的那个类型那么大,对于常用的基本数据类型来说,使用QVariant的代价就会变得特别大,而QVariant在Qt中属于比较核心的类,使用的地方太多,这显然不可行。那么实际上QVariant是怎么将各种数据类型和稀泥的呢?

 

思路

看了Qt助手里的介绍之后我还以为QVariant的实现不使用union。那就奇怪了,这么多类型放到一起,难道是void*加上类型转换实现的?看了Qt的源码之后发现其实里面使用了union,只是对基本数据类型和类类型做了区分,基本数据类型直接存值,类类型存指针,下面是这个union的定义:


 

细节

1.union Data中有三个成员是指针类型,QObject*o容易理解,当存储的是QObject类或子类类型的时候使用该成员,那么另外两个指针的作用是什么?

2.有三个成员是指针类型,那么对象真正的存储位置在哪,是动态分配?如果是动态分配,QVariant是如何管理这些资源的?

3.QVariant中有QVariant::type()等与类型判断有关的成员,并且在QVariant::toXXX转换失败时返回空对象或者不合法的对象,所以QVariant应该存储了值的类型信息。

 

实现

首先看一下QVariant的构造函数列表

 

class QVariant



 public:

   QVariant() noexcept : d() 

   ~QVariant();

   QVariant(Type type);

   QVariant(int typeId, const void *copy);

   QVariant(int typeId, const void *copy, uint flags);

   QVariant(const QVariant &other);

 

   QVariant(int i);

   QVariant(uint ui);

   QVariant(qlonglong ll);

   QVariant(qulonglong ull);

   QVariant(bool b);

   QVariant(double d);

   QVariant(float f);

 

   QVariant(const char *str);

 

   QVariant(const QByteArray &bytearray);

   QVariant(const QBitArray &bitarray);

   QVariant(const QString &string);

    QVariant(QLatin1String string);

   QVariant(const QStringList &stringlist);

   QVariant(QChar qchar);

   QVariant(const QDate &date);

   QVariant(const QTime &time);

   QVariant(const QDateTime &datetime);

   QVariant(const QList<QVariant> &list);

    QVariant(const QMap<QString,QVariant>&map);

   QVariant(const QHash<QString,QVariant> &hash);

 

         //geometry variant

   QVariant(const QSize &size);

   QVariant(const QSizeF &size);

   QVariant(const QPoint &pt);

   QVariant(const QPointF &pt);

   QVariant(const QLine &line);

   QVariant(const QLineF &line);

   QVariant(const QRect &rect);

   QVariant(const QRectF &rect);

 

   QVariant(const QLocale &locale);

        

   // regexp

   QVariant(const QRegExp &regExp);

        

         //bootstrapped

   QVariant(const QRegularExpression &re);

   QVariant(const QUrl &url);

   QVariant(const QEasingCurve &easing);

   QVariant(const QUuid &uuid);

   QVariant(const QModelIndex &modelIndex);

   QVariant(const QPersistentModelIndex &modelIndex);

   QVariant(const QJsonValue &jsonValue);

   QVariant(const QJsonObject &jsonObject);

   QVariant(const QJsonArray &jsonArray);

QVariant(const QJsonDocument &jsonDocument);

;


可以看到QVariant支持很多类型,从实现上分大概有两类:基本数据类型,类类型。但是所有的类类型都不是QObject子类,而且大部分没有父类。不同的基本数据类型或不同类类型实现相似,所以下面为了减少篇幅,本想列举部分实现,可是无非是各种类型判断和类型转换,不说了

以上是关于qvariant是如何和稀泥的的主要内容,如果未能解决你的问题,请参考以下文章

自定义数据类型使用QVariant转换的方法

QVariant::fromValue 是如何工作的?

QVariant.toXXX 函数的函数指针

如何将 QVariant::fromValue 与 QString 一起使用?

如何在 Qt 中将 QVariant 转换为 QString,反之亦然?

QVariant::QVariant(void*) 是私有的