• QVariant实质


    QVariant实质

    QVariant是一种可以存储不同类型的数据结构,在很多场合这是很有用得
    为了达到这种目的,可以想象,该对象应该存储对象的类型信息,数据信息以及其他辅助详细
    考虑用途,这种对象必须支持对不同对象的存储,对存储类型的检测以及取对象三个功能
    1.对象的存储
    代码见下:
    QVariant(Type type);
        QVariant(int typeOrUserType, const void *copy);
        QVariant(int typeOrUserType, const void *copy, uint flags);
        QVariant(const QVariant &other);

    #ifndef QT_NO_DATASTREAM
        QVariant(QDataStream &s);
    #endif

        QVariant(int i);
        QVariant(uint ui);
        QVariant(qlonglong ll);
        QVariant(qulonglong ull);
        QVariant(bool b);
        QVariant(double d);
        QVariant(float f) { d.is_null = false; d.type = QMetaType::Float; d.data.f = f; }
    #ifndef QT_NO_CAST_FROM_ASCII
        QT_ASCII_CAST_WARN_CONSTRUCTOR QVariant(const char *str);
    #endif

        QVariant(const QByteArray &bytearray);
        QVariant(const QBitArray &bitarray);
        QVariant(const QString &string);
        QVariant(const QLatin1String &string);
        QVariant(const QStringList &stringlist);
        QVariant(const 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);
    #ifndef QT_NO_GEOM_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);
    #endif
        QVariant(const QUrl &url);
        QVariant(const QLocale &locale);
    #ifndef QT_NO_REGEXP
        QVariant(const QRegExp &regExp);
    #endif
    #ifndef QT_BOOTSTRAPPED
        QVariant(const QEasingCurve &easing);
    #endif
        QVariant(Qt::GlobalColor color);
    2.QVariant Type
    在该对象中type负责记录对象的类型,这对于正确取出对象是很用得
    3.成员函数
    Type type() const;
        int userType() const;
        const char *typeName() const;

        bool canConvert(Type t) const;
        bool convert(Type t);

    #ifdef QT3_SUPPORT
        inline QT3_SUPPORT bool canCast(Type t) const
        { return canConvert(t); }
        inline QT3_SUPPORT bool cast(Type t)
        { return convert(t); }
    #endif
    这几个函数的用途很显然,看看其中一个的实现吧
    bool QVariant::canConvert(Type t) const
    {
        //we can treat floats as double
        //the reason for not doing it the "proper" way is that QMetaType::Float's value is 135,
        //which can't be handled by qCanConvertMatrix
        //In addition QVariant::Type doesn't have a Float value, so we're using QMetaType::Float
        const uint currentType = ((d.type == QMetaType::Float) ? QVariant::Double : d.type);
        if (uint(t) == uint(QMetaType::Float)) t = QVariant::Double;

        if (currentType == uint(t))
            return true;

        if (currentType > QVariant::LastCoreType || t > QVariant::LastCoreType) {
            switch (uint(t)) {
            case QVariant::Int:
                return currentType == QVariant::KeySequence
                       || currentType == QMetaType::ULong
                       || currentType == QMetaType::Long
                       || currentType == QMetaType::UShort
                       || currentType == QMetaType::UChar
                       || currentType == QMetaType::Char
                       || currentType == QMetaType::Short;
            case QVariant::Image:
                return currentType == QVariant::Pixmap || currentType == QVariant::Bitmap;
            case QVariant::Pixmap:
                return currentType == QVariant::Image || currentType == QVariant::Bitmap
                                  || currentType == QVariant::Brush;
            case QVariant::Bitmap:
                return currentType == QVariant::Pixmap || currentType == QVariant::Image;
            case QVariant::ByteArray:
                return currentType == QVariant::Color;
            case QVariant::String:
                return currentType == QVariant::KeySequence || currentType == QVariant::Font
                                  || currentType == QVariant::Color;
            case QVariant::KeySequence:
                return currentType == QVariant::String || currentType == QVariant::Int;
            case QVariant::Font:
                return currentType == QVariant::String;
            case QVariant::Color:
                return currentType == QVariant::String || currentType == QVariant::ByteArray
                                  || currentType == QVariant::Brush;
            case QVariant::Brush:
                return currentType == QVariant::Color || currentType == QVariant::Pixmap;
            case QMetaType::Long:
            case QMetaType::Char:
            case QMetaType::UChar:
            case QMetaType::ULong:
            case QMetaType::Short:
            case QMetaType::UShort:
                return qCanConvertMatrix[QVariant::Int] & (1 << currentType) || currentType == QVariant::Int;
            default:
                return false;
            }
        }

        if(t == String && currentType == StringList)
            return v_cast<QStringList>(&d)->count() == 1;
        else
            return qCanConvertMatrix[t] & (1 << currentType);
    }
    该函数作用是检测存储对象是否可以转换为输入类型,具体实现很明了
    4.QVariant对象的最后一个主要的功能就是到给定类型的转换
    函数簇如下:
    int toInt(bool *ok = 0) const;
        uint toUInt(bool *ok = 0) const;
        qlonglong toLongLong(bool *ok = 0) const;
        qulonglong toULongLong(bool *ok = 0) const;
        bool toBool() const;
        double toDouble(bool *ok = 0) const;
        float toFloat(bool *ok = 0) const;
        qreal toReal(bool *ok = 0) const;
        QByteArray toByteArray() const;
        QBitArray toBitArray() const;
        QString toString() const;
        QStringList toStringList() const;
        QChar toChar() const;
        QDate toDate() const;
        QTime toTime() const;
        QDateTime toDateTime() const;
        QList<QVariant> toList() const;
        QMap<QString, QVariant> toMap() const;
        QHash<QString, QVariant> toHash() const;
    其一个实现如下:
    /*!
        fn QTime QVariant::toTime() const

        Returns the variant as a QTime if the variant has type() l Time,
        l DateTime, or l String; otherwise returns an invalid time.

        If the type() is l String, an invalid time will be returned if
        the string cannot be parsed as a Qt::ISODate format time.

        sa canConvert(), convert()
    */
    QTime QVariant::toTime() const
    {
        return qVariantToHelper<QTime>(d, Time, handler);
    }
    使用了模板函数:qVariantToHelper
    5.关于qVariantToHelper
    /*!
        fn bool QVariant::isValid() const

        Returns true if the storage type of this variant is not
        QVariant::Invalid; otherwise returns false.
    */

    template <typename T>
    inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t,
                              const QVariant::Handler *handler, T * = 0)
    {
        if (d.type == t)
            return *v_cast<T>(&d);

        T ret;
        handler->convert(&d, t, &ret, 0);
        return ret;
    }
    该函数根据对象信息和目标类型做转换工作,如果二者类型一致,则直接做转换,否则交给函数handler->convert处理
    6.关于Handler对象
    struct Handler {
            f_construct construct;
            f_clear clear;
            f_null isNull;
    #ifndef QT_NO_DATASTREAM
            f_load load;
            f_save save;
    #endif
            f_compare compare;
            f_convert convert;
            f_canConvert canConvert;
            f_debugStream debugStream;
        };
    不过好像没看出什么门道,那就继续看看
    其实际结构为:
    const QVariant::Handler qt_kernel_variant_handler = {
        construct,
        clear,
        isNull,
    #ifndef QT_NO_DATASTREAM
        0,
        0,
    #endif
        compare,
        convert,
        0,
    #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
        streamDebug
    #else
        0
    #endif
    };
    再看其中 一个函数实现constuct
    static void construct(QVariant::Private *x, const void *copy)
    {
        x->is_shared = false;

        switch (x->type) {
        case QVariant::String:
            v_construct<QString>(x, copy);
            break;
        case QVariant::Char:
            v_construct<QChar>(x, copy);
            break;
        case QVariant::StringList:
            v_construct<QStringList>(x, copy);
            break;
        case QVariant::Map:
            v_construct<QVariantMap>(x, copy);
            break;
        case QVariant::Hash:
            v_construct<QVariantHash>(x, copy);
            break;
        case QVariant::List:
            v_construct<QVariantList>(x, copy);
            break;
        case QVariant::Date:
            v_construct<QDate>(x, copy);
            break;
        case QVariant::Time:
            v_construct<QTime>(x, copy);
            break;
        case QVariant::DateTime:
            v_construct<QDateTime>(x, copy);
            break;
        case QVariant::ByteArray:
            v_construct<QByteArray>(x, copy);
            break;
        case QVariant::BitArray:
            v_construct<QBitArray>(x, copy);
            break;
    #ifndef QT_NO_GEOM_VARIANT
        case QVariant::Size:
            v_construct<QSize>(x, copy);
            break;
        case QVariant::SizeF:
            v_construct<QSizeF>(x, copy);
            break;
        case QVariant::Rect:
            v_construct<QRect>(x, copy);
            break;
        case QVariant::LineF:
            v_construct<QLineF>(x, copy);
            break;
        case QVariant::Line:
            v_construct<QLine>(x, copy);
            break;
        case QVariant::RectF:
            v_construct<QRectF>(x, copy);
            break;
        case QVariant::Point:
            v_construct<QPoint>(x, copy);
            break;
        case QVariant::PointF:
            v_construct<QPointF>(x, copy);
            break;
    #endif
        case QVariant::Url:
            v_construct<QUrl>(x, copy);
            break;
        case QVariant::Locale:
            v_construct<QLocale>(x, copy);
            break;
    #ifndef QT_NO_REGEXP
        case QVariant::RegExp:
            v_construct<QRegExp>(x, copy);
            break;
    #endif
    #ifndef QT_BOOTSTRAPPED
        case QVariant::EasingCurve:
            v_construct<QEasingCurve>(x, copy);
            break;
    #endif
        case QVariant::Int:
            x->data.i = copy ? *static_cast<const int *>(copy) : 0;
            break;
        case QVariant::UInt:
            x->data.u = copy ? *static_cast<const uint *>(copy) : 0u;
            break;
        case QVariant::Bool:
            x->data.b = copy ? *static_cast<const bool *>(copy) : false;
            break;
        case QVariant::Double:
            x->data.d = copy ? *static_cast<const double*>(copy) : 0.0;
            break;
        case QMetaType::Float:
            x->data.f = copy ? *static_cast<const float*>(copy) : 0.0f;
            break;
        case QMetaType::QObjectStar:
            x->data.o = copy ? *static_cast<QObject *const*>(copy) : 0;
            break;
        case QVariant::LongLong:
            x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0);
            break;
        case QVariant::ULongLong:
            x->data.ull = copy ? *static_cast<const qulonglong *>(copy) : Q_UINT64_C(0);
            break;
        case QVariant::Invalid:
        case QVariant::UserType:
            break;
        default:
            void *ptr = QMetaType::construct(x->type, copy);
            if (!ptr) {
                x->type = QVariant::Invalid;
            } else {
                x->is_shared = true;
                x->data.shared = new QVariant::PrivateShared(ptr);
            }
            break;
        }
        x->is_null = !copy;
    }
    继续看v_construct
    该函数模板实现和平台有关,其中一个平台的实现如下:
    template <class T>
    inline void v_construct(QVariant::Private *x, const void *copy, T * = 0)
    {
        if (sizeof(T) > sizeof(QVariant::Private::Data)) {
            x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy))
                                  : new QVariantPrivateSharedEx<T>;
            x->is_shared = true;
        } else {
            if (copy)
                new (&x->data.ptr) T(*static_cast<const T *>(copy));
            else
                new (&x->data.ptr) T;
        }
    }
    这里主要是把传入对象指针导入为本身的数据指针data.ptr

    QVariant大致就这个样子
  • 相关阅读:
    IDETalk
    servlet概述
    过滤器(Filter)
    ieda常用快捷键
    UUID
    JRebel 7.0.10 for intellij IDEA 2017.1
    BP神经网络(手写数字识别)
    遗传算法解决TSP问题
    [CODEVS1258]关路灯
    [NOIP2007]统计数字
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/7816873.html
Copyright © 2020-2023  润新知