QVariant实质 (类似 C#中的装箱拆箱)
为了达到这种目的,可以想象,该对象应该存储对象的类型信息,数据信息以及其他辅助详细
考虑用途,这种对象必须支持对不同对象的存储,对存储类型的检测以及取对象三个功能
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 ®Exp);
#endif
#ifndef QT_BOOTSTRAPPED
QVariant(const QEasingCurve &easing);
#endif
QVariant(Qt::GlobalColor color);
在该对象中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
};
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;
}
该函数模板实现和平台有关,其中一个平台的实现如下:
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;
}
}
QVariant大致就这个样子
有时需要用同一个变量来保存不同类型的数据。一种方法是将数据编码为QByteArray 或QString。如串既可保存文本也可保存数字。Qt提供了一种更好的方式使用QVariant.
QVariant类可以保存许多Qt类型的值,包括QBrush, QColor, QCursor, QDateTime, QFont,QKeySequence, QPalette, QPen, QPixmap, QPoint, QRect, QRegion, QSize, 和QString,也包括基本的C++数字类型,如double和 int.还可保存容器如QMap, QStringList, 和 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)。
QVariant实质 (类似 C#中的装箱拆箱)的更多相关文章
- Java中的装箱拆箱
一) 装箱与拆箱 Java中有概念是一切皆对象,因为所有的类都默认继承自Object.但是,对于数据类型是个例外,如short,int,long,float,double, byte,char,bo ...
- CLR via C# 中关于装箱拆箱的摘录
装箱: 为了将一个值类型转换成一个引用类型,要使用一个名为装箱(boxing)的机制.下面总结了对值类型的一个实例进行装箱操作时在内部发生的事情. 1.在托管堆中分配好内存.分配的内存量是值类型的各 ...
- C#中的装箱拆箱
在C#中,经常需要把值类型和引用类型相互转换. 首先明确两条法则: 1.引用类型总是被分配到“堆”上. 2.值类型总是分配到它声明的地方: a.作为引用类型的成员变量分配到“堆”上 b.作为方法的局部 ...
- Java中的自动装箱拆箱
Java中的自动装箱拆箱 一.自动装箱与自动拆箱 自动装箱就是将基本数据类型转换为包装类类型,自动拆箱就是将包装类类型转换为基本数据类型. 1 // 自动装箱 2 Integer total = 90 ...
- NET中的类型和装箱/拆箱原理
谈到装箱拆箱,DebugLZQ相信给位园子里的博友一定可以娓娓道来,大概的意思就是值类型和引用类型的相互转换呗---值类型到引用类型叫装箱,反之则叫拆箱.这当然没有问题,可是你只知道这么多,那么Deb ...
- 读书笔记-C#中装箱拆箱性能
前言 最近在看王涛大神的<你必须知道的.NET(第二版)>一书,嗯,首先膜拜一下…. 在书中的第五章-品味类型中,对装箱与拆箱一节感触很深,概念本身相信每一个程序猿都不陌生,装 ...
- WPF中多线程统计拆箱装箱和泛型的运行效率
WPF中多线程统计拆箱装箱和泛型的执行效率.使用的知识点有泛型.多线程.托付.从样例中能够看到使用泛型的效率至少提升2倍 MainWindow.xaml <Window x:Class=&quo ...
- 如何理解Java中的自动拆箱和自动装箱?
小伟刚毕业时面的第一家公司就被面试官给问住了... 如何理解Java中的自动拆箱和自动装箱? 自动拆箱?自动装箱?什么鬼,听都没听过啊,这...这..知识盲区... 回到家后小伟赶紧查资料,我透,这不 ...
- C#装箱拆箱
. 装箱和拆箱是一个抽象的概念 2. 装箱是将值类型转换为引用类型 :拆箱是将引用类型转换为值类型 利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类 ...
随机推荐
- length prototype 函数function的属性,以及构造函数
前言:学到一些JavaScript高级的知识,在这里记下,方便以后的查找 1.length代表函数定义的形参的个数,挺简单的 例如:function Pen(price,cname) { . ...
- Ubuntu 16.04 - 64bit 解压 rar 报错 Parsing Filters not supported
Ubuntu 16.04 - 64bit 解压rar 文件报错: 错误如下图: 原因: 未安装解压命令 unrar 参考博客: Error - "Parsing Filters not s ...
- poj1274 匈牙利算法 二分图最大匹配
poj1274 题意: 有n个奶牛, m个畜舍, 每个畜舍最多装1头牛,每只奶牛只有在自己喜欢的畜舍里才能产奶. 求最大产奶量. 分析: 其实题意很明显, 二分图的最大匹配, 匈牙利算法. #incl ...
- LVS概述
LVS原理概述: lvs是一个开源软件,是Linux virtual server的简写,即linux虚拟服务器,是一个虚拟的服务器集群系统,lvs集群采用ip负载均衡技术和基于内容的请求分发技术.将 ...
- javascript异步执行函数导致的变量变化问题解决思路
for(var i=0;i<3;i++) { setTimeout(function(){ console.log(i) },0); }控制台输出:333 这是因为执行方法的时候for循环已经执 ...
- Codevs 2611 观光旅游(floyed最小环)
2611 观光旅游 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某旅游区里面有N个景点.两个景点之间可能直接有道路相连,用 ...
- OpenCV(3)-图像resize
在图像处理过程中,有时需要把图像调整到同样大小,便于处理,这时需要用到图像resize() 原函数 void resize(InputArray src, OutputArray dst, Size ...
- JS的词法作用域
词法作用域定义实现的规则: 1 函数作用域实在定义的时候决定的,而不是在执行时候决定 2 为了实现这种词法作用域,函数内部不仅包含函数代码逻辑,还必须引用当前的作用域链. 3 函数对象可以通过作用域链 ...
- TweenMax动画库学习(二)
目录 TweenMax动画库学习(一) TweenMax动画库学习(二) TweenMax动画库学习(三) Tw ...
- SQL技术内幕四
数据类型: sql server只接受两种数据类型 1. 普通字符 varchar char 用一个字节表示一个字符,表示英文 2.unicode nchar nvarchar 用两个字节表示一个 ...