QByteArray 和 QVariant

2018-10-08 09:53 更新

QByteArray 和 QVariant

前面我們在介紹 QString 的最后部分曾經(jīng)提到了 QByteArray 這個類。現(xiàn)在我們就首先對這個類進(jìn)行介紹。

QByteArray 具有類似與 QString 的 API。它也有相應(yīng)的函數(shù),比如 left(), right(), mid()等。這些函數(shù)不僅名字和 QString 一樣,而且也具有幾乎相同的功能。QByteArray 可以存儲原生的二進(jìn)制數(shù)據(jù)和8位編碼的文本數(shù)據(jù)。這句話怎么理解呢?我們知道,計算機(jī)內(nèi)部所有的數(shù)據(jù)都是以0和1的形式存儲的。這種形式就是二進(jìn)制。比如一串0、1代碼:1000,計算機(jī)并不知道它代表的是什么,這需要由上下文決定:它可以是整數(shù)8,也可以是一個 ARGB 的顏色(準(zhǔn)確的說,整數(shù)8的編碼并不是這么簡單,但我們姑且這個理解吧)。對于文件,即便是一個文本文件,讀出時也可以按照二進(jìn)制的形式讀出,這就是二進(jìn)制格式。如果把這些二進(jìn)制的0、1串按照編碼解釋成一個個字符,就是文本形式了。因此,QByteArray 實(shí)際上是原生的二進(jìn)制,但是也可以當(dāng)作是文本,因此擁有文本的一些操作。但是,我們還是建議使用 QString 表示文本,重要的原因是,QString 支持 Unicode。

為了方便期間,QByteArray 自動的保證“最后一個字節(jié)之后的那個位”是'\0'。這就使得 QByteArray可以很容易的轉(zhuǎn)換成 const char *,也就是上一章節(jié)中我們提到的那兩個函數(shù)。同樣,作為原生二進(jìn)制存儲,QByteArray 中間也可以存儲'\0',而不必須是'\0'在最后一位。

在有些情況下,我們希望把數(shù)據(jù)存儲在一個變量中。例如,我有一個數(shù)組,既希望存整數(shù),又希望存浮點(diǎn)數(shù),還希望存 string。對于 Java 來說,很簡單,只要把這個數(shù)組聲明成 Object[]類型的。這是什么意思呢?實(shí)際上,這里用到的是繼承。在 Java 中,int 和 float 雖然是原生數(shù)據(jù)類型,但是它們都有分別對應(yīng)一個包裝類 Integer 和 Float。所有這些 Integer、Float 和 String 都是繼承于Object,也就是說,Integer、Float 和 String 都是一個(也就是 is-a 的關(guān)系)Object,這樣,Object 的數(shù)組就可以存儲不同的類型。但是,C++中沒有這樣一個 Object 類,原因在于,Java 是單根的,而 C++不是。在 Java 中,所有類都可以上溯到 Object 類,但是 C++中沒有這么一個根。那么,怎么實(shí)現(xiàn)這么的操作呢?一種辦法是,我們都存成 string 類,比如 int i=10,我就存"10"字符串。簡單的數(shù)據(jù)類型固然可以,可復(fù)雜一些的呢?比如一個顏色?難道要把 ARGB 所有的值都轉(zhuǎn)化成string?這種做法很復(fù)雜,而且失去了 C++的類型檢查等好處。于是我們想另外的辦法:創(chuàng)建一個Object 類,這是一個“很大很大的”類,里面存儲了幾乎所有的數(shù)據(jù)類型,比如下面的代碼:


class Object  
{  
public:  
    int intValue;  
    float floatValue;  
    string stringValue;  
}; 

這個類怎么樣?它就足以存儲 int、float 和 string 了。嗯,這就是我們的思路,也是 Qt 的思路。在 Qt 中,這樣的類就是 QVariant。

QVariant 可以保存很多 Qt 的數(shù)據(jù)類型,包括 QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize 和 QString,并且還有 C++基本類型,如 int、float 等。QVariant 還能保存很多集合類型,如 QMap<QString, QVariant>, QStringList 和 QList。item view classes,數(shù)據(jù)庫模塊和 QSettings 都大量使用了 QVariant 類,,以方便我們讀寫數(shù)據(jù)。QVariant 也可以進(jìn)行嵌套存儲,例如


QMap<QString, QVariant> pearMap;  
pearMap["Standard"] = 1.95;  
pearMap["Organic"] = 2.25;  

QMap<QString, QVariant> fruitMap;  
fruitMap["Orange"] = 2.10;  
fruitMap["Pineapple"] = 3.85;  
fruitMap["Pear"] = pearMap;

QVariant 被用于構(gòu)建 Qt Meta-Object,因此是 QtCore 的一部分。當(dāng)然,我們也可以在 GUI 模塊中使用,例如


QIcon icon("open.png");  
QVariant variant = icon;  
// other function  
QIcon icon = variant.value<QIcon>(); 

我們使用了 value()模版函數(shù),獲取存儲在 QVariant 中的數(shù)據(jù)。這種函數(shù)在非 GUI 數(shù)據(jù)中同樣適用,但是,在非 GUI 模塊中,我們通常使用 toInt()這樣的一系列 to...()函數(shù),如 toString()等。

如果你覺得 QVariant 提供的存儲數(shù)據(jù)類型太少,也可以自定義 QVariant 的存儲類型。被 QVariant 存儲的數(shù)據(jù)類型需要有一個默認(rèn)的構(gòu)造函數(shù)和一個拷貝構(gòu)造函數(shù)。為了實(shí)現(xiàn)這個功能,首先必須使用 Q_DECLARE_METATYPE()宏。通常會將這個宏放在類的聲明所在頭文件的下面:


Q_DECLARE_METATYPE(BusinessCard) 

然后我們就可以使用:


BusinessCard businessCard;  
QVariant variant = QVariant::fromValue(businessCard);  
// ...  
if (variant.canConvert<BusinessCard>()) {  
    BusinessCard card = variant.value<BusinessCard>();  
    // ...  
}

由于 VC 6的編譯器限制,這些模板函數(shù)不能使用,如果你使用這個編譯器,需要使用qVariantFromValue(), qVariantValue()和 qVariantCanConvert()這三個宏。如果自定義數(shù)據(jù)類型重寫了<<和>>運(yùn)算符,那么就可以直接在 QDataStream 中使用。不過首先需要使用 qRegisterMetaTypeStreamOperators().宏進(jìn)行注冊。這就能夠讓 QSettings 使用操作符對數(shù)據(jù)進(jìn)行操作,例如


qRegisterMetaTypeStreamOperators<BusinessCard>("BusinessCard"); 

本文出自 “豆子空間” 博客,請務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/193918

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號