zoukankan      html  css  js  c++  java
  • 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大致就这个样子
  • 相关阅读:
    [ jquery 选择器 :hidden ] 此方法选取匹配所有不可见元素,或者type为hidden的元素
    剑指 Offer 03. 数组中重复的数字 哈希
    LeetCode 1736. 替换隐藏数字得到的最晚时间 贪心
    Leetcode 1552. 两球之间的磁力 二分
    Leetcode 88. 合并两个有序数组 双指针
    LeetCode 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
    LeetCode 1743. 相邻元素对还原数组 哈希
    LeetCode 1745. 回文串分割 IV dp
    剑指 Offer 47. 礼物的最大价值 dp
    剑指 Offer 33. 二叉搜索树的后序遍历序列 树的遍历
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/7816873.html
Copyright © 2011-2022 走看看