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大致就这个样子

QVariant实质的更多相关文章

  1. QVariant实质 (类似 C#中的装箱拆箱)

    QVariant是一种可以存储不同类型的数据结构,在很多场合这是很有用得为了达到这种目的,可以想象,该对象应该存储对象的类型信息,数据信息以及其他辅助详细考虑用途,这种对象必须支持对不同对象的存储,对 ...

  2. C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理

    这里的问题实质是我们在头文件中直接定义全局变量或者函数,却分别在主函数和对应的cpp文件中包含了两次,于是在编译的时候这个变量或者函数被定义了两次,问题就出现了,因此,我们应该形成一种编码风格,即: ...

  3. 微信小程序实质是什么? Hybrid App

    微信小程序是一种不需要下载安装即可使用的应用,用户扫一扫或者搜一下即可打开应用.微信小程序实质是Hybrid技术的应用.Hybrid App(混合模式移动应用). 小程序能够更多的可以更多的调用手机本 ...

  4. async/await的实质理解

    async/await关键字能帮助开发者更容易地编写异步代码.但不少开发者对于这两个关键字的使用比较困惑,不知道该怎么使用.本文就async/await的实质作简单描述,以便大家能更清楚理解. 一.a ...

  5. QVariant与自定义数据类型转换的方法

      在使用VC.Delphi编写用户界面程序的时候,经常会把对象与控件的data域进行绑定,便于程序运行中读写提高效率.然而在Qt编程中怎么实现这个功能呢?比如将一个用户自定义的结构体与QComboB ...

  6. QVariant类学习(非常强大的类型,甚至能处理QMap<QString ,QVariant>)

    详细描述: QVariant类作为一个最为普遍的Qt数据类型的联合. 因为c++禁止没有构造函数和析构函数的联合体,许多继承的Qt类不能够在联合体当中使用.(联合体当中的变量共用一个存储区),没有了联 ...

  7. QVariant(相当于是Java里面的Object,起到一个数据类型“擦除”的作用,可以使用Q_DECLARE_METATYPE进行注册)

    =QVariant= [%这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是 ...

  8. 董事长、总裁与CEO的区别与实质

    自从信息产业兴起以来,尤其是网络股泡沫产生以来,“CEO”在中国骤然成为一个流行词汇.总经理和总裁们纷纷改称CEO,这个缩写词比它的中译版“首席执行官”更简洁,在中国人心目中更有神圣感,于是便出现了今 ...

  9. qsettings 保存自定义结构体(QVariant与自定义结构体相互转化)

    参考博文:QVariant与自定义数据类型转换的方法. 这里摘取其关键内容: 1.将自定义数据类型使用Q_DECLARE_METATYPE宏进行声明,便于编译器识别. 2.在插入对象的时候,声明QVa ...

随机推荐

  1. AngularJS中Directive指令系列

    近段时间在研究Angular中的directive用法,打算写个系列.以官方文档为主.并参考诸多教程.加上自己的思考. 基本概念及用法 scope属性的使用.  &, <, =, @ 符 ...

  2. ABP 框架集成EF批量增加、删除、修改只针对使用mmsql的

    AppService 层使用nuget 添加 EFCore.BulkExtensions 引用 using Abp.Application.Services.Dto; using Abp.Domain ...

  3. C#Framework4.0支持异步async/await语法

    由于用户使用的是XP系统,但是程序里异步都是通过async/await代码来实现的,然而async/await需要Framework4.5版本才可以,而XP系统最高只能支持到Framework4.0, ...

  4. windows环境下apache-apollo服务器搭建及发布订阅测试

    查证了一些资料之后,发现 apache-apollo服务器使用的人还是挺多的,资料也比较齐全,所以直接选择 apache-apollo了,具体性能如何,先用起来再说吧: 1.下载 apache-apo ...

  5. 时序数据库InfluxDB

    在系统服务部署过后,线上运行服务的稳定性是系统好坏的重要体现,监控系统状态至关重要,经过调研了解,时序数据库influxDB在此方面表现优异. influxDB介绍 时间序列数据是以时间字段为每行数据 ...

  6. CSP201403-3:命令行选项

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  7. phpldapadmin具体设置

    一.需求    1.属性隐藏 只显示用户名,部门(因为是单OU设计为了做区分),登录密码 2.属性顺序显示 部门>用户名>登录密码 3.使用UID可以登陆 用户可以使用账户(自己的名字)登 ...

  8. sqlserver-查阻塞

    模拟阻塞: 打开两个窗口:     窗口一: BEGIN TRANSACTION--开始事务 --等待1分钟 WAITFOR DELAY '00:1'; 窗口二: 查询阻塞:(当前被阻塞的进程id,不 ...

  9. ES6的新特性(4)——字符串的扩展

    字符串的扩展 ES6 加强了对 Unicode 的支持,并且扩展了字符串对象. 字符的 Unicode 表示法 JavaScript 允许采用\uxxxx形式表示一个字在\u0000~\uFFFF之间 ...

  10. 按照Right-BICEP要求设计四则运算3程序的单元测试用例

    按照Right-BICEP要求: Right——结果是否正确? B——是否所有的边界条件都是正确的? I——能查一下反响关联吗? C——能用其它手段交叉检查一下吗? E——你是否可以强制错误条件发生? ...