zoukankan      html  css  js  c++  java
  • QVariant实质 (类似 C#中的装箱拆箱)

    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<</SPAN>QVariant> &list);
    QVariant(const QMap<</SPAN>QString,QVariant> &map);
    QVariant(const QHash<</SPAN>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<</SPAN>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<</SPAN>QVariant> toList() const;
    QMap<</SPAN>QString, QVariant> toMap() const;
    QHash<</SPAN>QString, QVariant> toHash() const;
    其一个实现如下:

    QTime QVariant::toTime() const
    {
    return qVariantToHelper<</SPAN>QTime>(d, Time, handler);
    }
    使用了模板函数:qVariantToHelper
    5.关于qVariantToHelper


    template <</SPAN>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<</SPAN>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<</SPAN>QString>(x, copy);
    break;
    case QVariant::Char:
    v_construct<</SPAN>QChar>(x, copy);
    break;
    case QVariant::StringList:
    v_construct<</SPAN>QStringList>(x, copy);
    break;
    case QVariant::Map:
    v_construct<</SPAN>QVariantMap>(x, copy);
    break;
    case QVariant::Hash:
    v_construct<</SPAN>QVariantHash>(x, copy);
    break;
    case QVariant::List:
    v_construct<</SPAN>QVariantList>(x, copy);
    break;
    case QVariant::Date:
    v_construct<</SPAN>QDate>(x, copy);
    break;
    case QVariant::Time:
    v_construct<</SPAN>QTime>(x, copy);
    break;
    case QVariant::DateTime:
    v_construct<</SPAN>QDateTime>(x, copy);
    break;
    case QVariant::ByteArray:
    v_construct<</SPAN>QByteArray>(x, copy);
    break;
    case QVariant::BitArray:
    v_construct<</SPAN>QBitArray>(x, copy);
    break;
    #ifndef QT_NO_GEOM_VARIANT
    case QVariant::Size:
    v_construct<</SPAN>QSize>(x, copy);
    break;
    case QVariant::SizeF:
    v_construct<</SPAN>QSizeF>(x, copy);
    break;
    case QVariant::Rect:
    v_construct<</SPAN>QRect>(x, copy);
    break;
    case QVariant::LineF:
    v_construct<</SPAN>QLineF>(x, copy);
    break;
    case QVariant::Line:
    v_construct<</SPAN>QLine>(x, copy);
    break;
    case QVariant::RectF:
    v_construct<</SPAN>QRectF>(x, copy);
    break;
    case QVariant::Point:
    v_construct<</SPAN>QPoint>(x, copy);
    break;
    case QVariant::PointF:
    v_construct<</SPAN>QPointF>(x, copy);
    break;
    #endif
    case QVariant::Url:
    v_construct<</SPAN>QUrl>(x, copy);
    break;
    case QVariant::Locale:
    v_construct<</SPAN>QLocale>(x, copy);
    break;
    #ifndef QT_NO_REGEXP
    case QVariant::RegExp:
    v_construct<</SPAN>QRegExp>(x, copy);
    break;
    #endif
    #ifndef QT_BOOTSTRAPPED
    case QVariant::EasingCurve:
    v_construct<</SPAN>QEasingCurve>(x, copy);
    break;
    #endif
    case QVariant::Int:
    x->data.i = copy ? *static_cast<</SPAN>const int *>(copy) : 0;
    break;
    case QVariant::UInt:
    x->data.u = copy ? *static_cast<</SPAN>const uint *>(copy) : 0u;
    break;
    case QVariant::Bool:
    x->data.b = copy ? *static_cast<</SPAN>const bool *>(copy) : false;
    break;
    case QVariant::Double:
    x->data.d = copy ? *static_cast<</SPAN>const double*>(copy) : 0.0;
    break;
    case QMetaType::Float:
    x->data.f = copy ? *static_cast<</SPAN>const float*>(copy) : 0.0f;
    break;
    case QMetaType::QObjectStar:
    x->data.o = copy ? *static_cast<</SPAN>QObject *const*>(copy) : 0;
    break;
    case QVariant::LongLong:
    x->data.ll = copy ? *static_cast<</SPAN>const qlonglong *>(copy) : Q_INT64_C(0);
    break;
    case QVariant::ULongLong:
    x->data.ull = copy ? *static_cast<</SPAN>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 <</SPAN>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<</SPAN>T>(*static_cast<</SPAN>const T *>(copy))
    : new QVariantPrivateSharedEx<</SPAN>T>;
    x->is_shared = true;
    } else {
    if (copy)
    new (&x->data.ptr) T(*static_cast<</SPAN>const T *>(copy));
    else
    new (&x->data.ptr) T;
    }
    }
    这里主要是把传入对象指针导入为本身的数据指针data.ptr

    QVariant大致就这个样子
    http://blog.sina.com.cn/s/blog_a401a1ea0101i8k9.html
     
    --------------------------------------------------------------------------------------------------------------------

    有时需要用同一个变量来保存不同类型的数据。一种方法是将数据编码为QByteArray QString。如串既可保存文本也可保存数字。Qt提供了一种更好的方式使用QVariant.

    QVariant类可以保存许多Qt类型的值,包括QBrushQColorQCursorQDateTimeQFont,QKeySequenceQPaletteQPenQPixmapQPointQRectQRegionQSizeQString,也包括基本的C++数字类型,如double int.还可保存容器如QMapQStringList QList

    使用QVariant通过嵌套容器类型值,可以创建任意复杂的数据结构:

     

    QMap pearMap;

    pearMap["Standard"] = 1.95;

    pearMap["Organic"] = 2.25;

    QMap fruitMap;

    fruitMap["Orange"] = 2.10;

    fruitMap["Pineapple"] = 3.85;

    fruitMap["Pear"] = pearMap;

     

    此处我们创建了一个map,拥有string键(产品名),值要么是浮点数(价格)或要么是map。顶层map有三个键:"Orange", "Pear", 和 "Pineapple"。与"Pear"键相对应的值是一个map,含有两个键("Standard" and "Organic").当遍历保存可变值的map时,需要用type()来检查类型。

     

    创建这样的数据结构看起来很好,但QVariant以牺牲效率和可读性为代价。所以通常定义一个恰当的C++类来保存数据。

     

    QIcon icon("open.png");

    QVariant variant = icon;

     

    为获得来自QVariant的GUI-related类型的值,可使用QVariant::value()模板函数:

    QIcon icon = variant.value();

    value()函数也用于非GUI数据类型与QVariant之间的转换,但实际上我们经常使用to...()转换函数(如,toString())。

    QVariant也能用于保存自定义的数据类型,假设这些类型能提供一个默认构造函数和拷贝构造函数。因此,首先要用Q_DECLARE_METATYPE()宏注册该类型,特别是在头文件中类定义的下面:

     

    Q_DECLARE_METATYPE(BusinessCard)

    代码如下:

    BusinessCard businessCard;

    QVariant variant = QVariant::fromValue(businessCard);

    ...

    if (variant.canConvert()) {

    BusinessCard card = variant.value();

    ...

    }

     

    因受编译器的限制,MSVC 6不能获得这些模板函数。如果想用这种编译器,使用qVariantFromValue(), qVariantValue(), 和 qVariantCanConvert()全局函数。

    如果自定义数据类型有<< 和 >>运算符用于QDataStream的写和读,可以使用qRegisterMetaTypeStreamOperators()注册这些运算符。这样就可以使用QSettings来保存自定义类型的参数。如:

    qRegisterMetaTypeStreamOperators("BusinessCard");

     

    Qt还提供其它的一些容器。QPair只保存两个值,类似于std::pair. QBitArray会在第十九章中使用。QVarLengthArray是一个对QVector的低级替代,因为它在栈上分配内存不能implicitly shared,它的overhead比QVector的少,所以它更适合紧循环(tight loops)。
     
    http://blog.sina.com.cn/s/blog_a401a1ea0101f8nv.html
  • 相关阅读:
    【Oracle】外部程序连接Oracle库之前的准备工作
    【Oracle】ora-12514的问题的解决
    Java8 LocalTime处理小结
    No serializer found for class com.hy.myapp.rest.VarietyInfo and no properties discovered to create BeanSerializer
    【Design Pattern】将职责链模式应用到Rest服务中去
    大商所交易品种和交易时间
    【RestTemplate】post请求示例
    【Pyton】访问Java提供的Rest接口示例
    【RestController】Restful接口获取请求者IP地址
    [HTML]锚点定义,链接跳转到锚点,JS跳转到锚点
  • 原文地址:https://www.cnblogs.com/findumars/p/5935035.html
Copyright © 2011-2022 走看看