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 ®Exp); #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大致就这个样子