Qt 對象序列化/反序列化

閱讀本文大概需要 3 分鐘

背景

日常開發過程中,避免不了對象序列化和反序列化,如果你使用 Qt 進行開發,那么有一種方法實現起來非常簡單和容易。

實現

我們知道 Qt 的元對象系統非常強大,基于此屬性我們可以實現對象的序列化和反序列化操作。

比如有一個學生類,包含以下幾個字段:學號、姓名、性別、出生日期等,定義如下類結構:

class DStudent : public QObject
{Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName)Q_PROPERTY(QString number READ number WRITE setNumber)Q_PROPERTY(QString sex READ sex WRITE setSex)Q_PROPERTY(QDateTime birthday READ birthday WRITE setBirthda)
public:explicit DStudent(QObject *parent = nullptr);QString name() const;void setName(const QString &newName);QString number() const;void setNumber(const QString &newNumber);QString sex() const;void setSex(const QString &newSex);QDateTime birthday() const;void setBirthda(const QDateTime &newBirthday);//...

需要增加那些字段,只需要在上述屬性位置繼續追加即可,通過把需要反射的字段定義成屬性,我們就可以遍歷該類的元對象,進而獲取其中的屬性信息。

序列化 Json

QJsonObject DStudent::toJson()
{QJsonObject jsObj = KJsonHelp::object2Json(this);return jsObj;
}
bool DStudent::fromJson(const QJsonObject &jsObj)
{return KJsonHelp::json2Object(jsObj, this);
}

核心代碼封裝到工具類中,方便其它地方調用,詳細實現如下:

QJsonObject KJsonHelp::object2Json(QObject *object)
{QJsonObject jsObj;if(nullptr == object){return jsObj;}const QMetaObject *pMetaObj = object->metaObject();for(int i = 0; i < pMetaObj->propertyCount(); i++){auto proName = pMetaObj->property(i).name();jsObj.insert(proName, QJsonValue::fromVariant(object->property(proName)));}if(jsObj.contains("objectName")){jsObj.remove("objectName");}return jsObj;
}bool KJsonHelp::json2Object(const QJsonObject &jsObj, QObject *object)
{if (jsObj.isEmpty() || nullptr == object){return false;}QStringList list;const QMetaObject *pMetaObj = object->metaObject();for(int i = 0; i < pMetaObj->propertyCount(); i++){list << pMetaObj->property(i).name();}QStringList jsonKeys = jsObj.keys();foreach(const QString &proName ,list){if(!jsonKeys.contains(proName) || jsObj.value(proName).isNull()){continue;}object->setProperty(proName.toLocal8Bit().data(), jsObj.value(proName));}return true;
}

任意一個繼承 QObject的對象都可以獲取到它的元對象,接著可以獲取到屬性個數,然后挨個進行遍歷即可。

如果想序列化到其他格式的,比如XML,在上述方法中根據 XML 規則生成即可,這個不是本文的重點。

一些坑和注意點

當然了并不是所有的類型都支持這種方式自動生成字段的,一些特殊類型或者自定義的類需要自己特殊去實現。

我們可以在上述學生類中,繼續添加新的測試屬性字段,來看看輸出的結果:

    // custome typeQ_PROPERTY(DScore sScore READ sScore WRITE setSScore)// test other typeQ_PROPERTY(int testInt READ testInt WRITE setTestInt)Q_PROPERTY(bool testBool READ testBool WRITE setTestBool)Q_PROPERTY(double testDouble READ testDouble WRITE setTestDouble)Q_PROPERTY(char testChar READ testChar WRITE setTestChar)Q_PROPERTY(QUrl testUrl READ testUrl WRITE setTestUrl)Q_PROPERTY(QVariant testV READ testV WRITE setTestV)Q_PROPERTY(QStringList testStringList READ testStringList WRITE setTestStringList)Q_PROPERTY(QRect testRect READ testRect WRITE setTestRect)Q_PROPERTY(QSize testSize READ testSize WRITE setTestSize)Q_PROPERTY(QPoint testPoint READ testPoint WRITE setTestPoint)Q_PROPERTY(QList<int> testIntList READ testIntList WRITE setTestIntList)Q_PROPERTY(QList<QString> testListString READ testListString WRITE setTestListString)

打印輸出:

    qRegisterMetaType<DScore>("DScore");DStudent st;st.setName(QStringLiteral("法外狂徒張三"));st.setNumber("123456789");st.setSex(QStringLiteral("男"));st.setBirthda(QDateTime::currentDateTime());// test other typest.setTestInt(10);st.setTestBool(true);st.setTestV(12);st.setTestDouble(12.121212);st.setTestChar('k');        //->stringst.setTestUrl(QUrl("http://kevinlq.com/")); // -> stringst.setTestStringList(QStringList() << "stringList1" << "stringList2");st.setTestRect(QRect(10,10,10,10));             // nullst.setTestSize(QSize(10,10));                   // nullst.setTestPoint(QPoint(10, 10));                // nullst.setTestIntList({11, 12});                    // nullst.setTestListString({"kevinlq", "devstone"});  // nullDScore score;score.setName("computer");score.setNumber("001");st.setSScore(score);                            // nullqDebug() << "st:" << st.toJson();
st: QJsonObject({"birthday":"2023-08-05T19:33:14.815","name":"法外狂徒張三","number":"123456789","sScore":null,"sex":"男","testBool":true,"testChar":"k","testDouble":12.121212,"testInt":10,"testIntList":null,"testListString":null,"testPoint":null,"testRect":null,"testSize":null,"testStringList":["stringList1","stringList2"],"testUrl":"http://kevinlq.com/","testV":12})

可以看到很多字段的值是 null,出現這種問題表示這個類型目前無法直接自動生成,如果你缺失需要這種結構,那么需要自行在序列化函數中進行特殊處理,比如自定義的類型處理:

QJsonObject DStudent::toJson()
{QJsonObject jsObj = KJsonHelp::object2Json(this);jsObj.insert("sScore", m_sScore.toJson());return jsObj;
}

上述對定義的課程類,進行了特殊處理,再次編譯后,輸出的結果如下:

{"birthday": "2023-08-05T23:27:00.757","name": "法外狂徒張三","number": "123456789","sScore": {"name": "computer","number": "001"}
}

可以看到正常輸出了我們需要的類型,其他類型可以照葫蘆畫瓢。

進階

是不是發現問題了,隨著你的類屬性字段越來越多,手寫這么多字段肯定非常累,能否自動生成這些重復的代碼呢,答案是可以的,結合前面的文章,就可以編寫一份更加緊湊的代碼了,詳細見這里 http://kevinlq.com/2023/01/16/generateProperty/

總結

序列化其實有很應用場景,以下是工作站經常使用的小 case:

  • 持久化保存類對象,及保存數據到本地磁盤;
  • socket 傳輸數據,需要把 json/xml/other 類型轉為對象,用對象進行業務處理;
  • 數據庫操作:從 db 中讀取出來的值序列化成對象,方便業務進行處理(使用 ORM 框架例外)
  • 和界面交互,比如界面使用 QML 編寫,那么大部分超場景會使用到 JSON。
  • 其他:待補充……

參考文檔

  • c++自動生成get/set方法

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/37033.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/37033.shtml
英文地址,請注明出處:http://en.pswp.cn/news/37033.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

智能家居(3)---socket網絡控制線程封裝

封裝socket網絡線程實現對智能家居中各種燈光的控制 main.Pro(主函數) #include <stdio.h> #include "controlDevice.h" #include "inputCommand.h" #include <pthread.h>struct Devices *pdeviceHead NULL; //設備工廠鏈表…

ES踩坑記錄之UNASSIGNED分片無法恢復

問題背景 換節點 我們線上有一套ES集群&#xff0c;三臺機器&#xff0c;共運行了6個節點。一直在線上跑了幾個月也一直沒出什么問題。然而好巧不巧&#xff0c;就在昨天&#xff0c;集群中的3號節點磁盤出現故障&#xff0c;導致機器直接癱瘓。本來大家覺得問題不大&#xf…

HTML和JavaScript實現一個簡單的計算器

使用HTML和JavaScript實現一個簡單的計算器。 一、繪制鍵盤 <!DOCTYPE html> <html> <head><title>Simple Calculator</title><style>.calculator {display: grid;grid-template-columns: repeat(4, 1fr);grid-gap: 5px;padding: 10px;}.…

【elementUi】繪制自定義表格、繪制曲線表格

要求繪制下圖系列表格&#xff1a; 實現步驟: 1.繪制樹&#xff0c;實現樹勾選字段—>表格繪制字段 邏輯&#xff1a; 樹&#xff1a;check-change“treeChart.handleCheckChange” 綁定點擊選擇事件&#xff0c;改變data.column3數據項&#xff1b;表格:columns"data…

基于 Nginx All In One 的 Outline Wiki 部署方法

1. Outline 簡介 官網&#xff1a;https://www.getoutline.com/ Outline 是一個開源的知識庫和團隊協作工具&#x1f9e0;&#xff0c;旨在幫助團隊共享、組織和協作文檔&#x1f4dd;。它提供了一個簡潔的界面&#xff0c;使用戶能夠輕松創建、編輯和查看文檔。 以下是 Out…

Ajax 筆記(四)—— Ajax 進階

筆記目錄 4. Ajax 進階4.1 同步代碼和異步代碼4.2 回調函數地獄4.2.1 解決方法一&#xff1a;Promise 鏈式調用4.2.2 解決方法二&#xff1a;async 函數和 await 4.3 Promise.all 靜態方法4.4 事件循環4.4.1 事件循環4.4.2 宏任務與微任務 4.5 案例4.5.1 案例一-商品分類4.5.2 …

讀書筆記 |【項目思維與管理】? 項目成為一種生存方式

讀書筆記 |【項目思維與管理】? 項目成為一種生存方式 一、理解項目固有的挑戰二、項目對企業的價值三、知識型企業的經營邏輯四、做項目管理的推進者 &#x1f496;The Begin&#x1f496;點點關注&#xff0c;收藏不迷路&#x1f496; 項目無處不在&#xff0c;項目已經成為…

智慧建筑工地平臺,通過信息化技術、物聯網、人工智能技術,實現對施工全過程的實時監控、數據分析、智能管理和優化調控

智慧工地是指通過信息化技術、物聯網、人工智能技術等手段&#xff0c;對建筑工地進行數字化、智能化、網絡化升級&#xff0c;實現對施工全過程的實時監控、數據分析、智能管理和優化調控。智慧工地的建設可以提高工地的安全性、效率性和質量&#xff0c;降低施工成本&#xf…

分布式唯一ID實戰

目錄 一、UUID二、數據庫方式1、數據庫生成之簡單方式2、數據庫生成 - 多臺機器和設置步長&#xff0c;解決性能問題3、Leaf-segment 方案實現4、雙 buffer 優化5、Leaf高可用容災 三、基于Redis實現分布式ID四、雪花算法 一、UUID UUID的標準形式包含32個16進制數字&#xff…

Word 2019打開.doc文檔后圖片和公式不顯示(呈現為白框)的解決辦法

Word 2019打開.doc文檔后圖片和公式不顯示&#xff08;呈現為白框&#xff09;的解決辦法 目錄 Word 2019打開.doc文檔后圖片和公式不顯示&#xff08;呈現為白框&#xff09;的解決辦法一、問題描述二、解決方法1.打開 WORD 2019&#xff0c;點擊菜單中的“文件”&#xff1b;…

微服務05-Sentinel流量防衛兵

隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分布式、多語言異構化服務架構的流量治理組件,主要以 流量 為切入點,從流量路由、流量控制、流量整形、熔斷降級、系統自適應過載保護、熱點流量防護等多個維度來幫助開發者保障微服務的穩定性。 S…

FBB簡介

FBB FBB簡介FBB組網名詞解釋FBB組網&#xff08;從下至上&#xff09;小結 FBB簡介 FBB&#xff1a;Fixed BroadBand&#xff0c;固定寬帶網絡&#xff0c;是一種依托線纜介質進行傳輸的地面有線網絡&#xff0c;區分與MBB&#xff0c;MBB是移動網絡。 MBB是天上一張網&#x…

學習Vue:簡介和優勢

什么是 Vue.js&#xff1f; Vue.js 是一個用于構建用戶界面的漸進式 JavaScript 框架。它專注于視圖層&#xff0c;并且可以輕松地集成到現有的項目中。Vue.js 的設計理念是漸進式&#xff0c;這意味著您可以根據項目的需要逐步引入 Vue.js&#xff0c;從而更好地控制應用的復…

專注于創意設計,為您的小程序和網站建設帶來更多的可能性

隨著移動互聯網的快速發展&#xff0c;越來越多的企業開始關注小程序和網站建設&#xff0c;以此來拓展業務和提升品牌形象。 在這個領域中&#xff0c;創意設計扮演著關鍵的角色。它不僅可以幫助企業打造獨特的形象和品牌&#xff0c;還能夠提高用戶體驗和購買決策的效率。 因…

Openlayers 實戰 - 地圖視野(View)- 圖層 -(layer)- 資源(source)顯示等級設置。

Openlayers 實戰 - 地圖視野&#xff08;View&#xff09;- 圖層 -&#xff08;layer&#xff09;- 資源&#xff08;source&#xff09;顯示等級設置。 問題原因核心代碼完整代碼&#xff1a;在線示例 在以往的項目維護中&#xff0c;出現一個問題&#xff0c;使用最新高清底圖…

已有公司將ChatGPT集成到客服中心以增強用戶體驗

Ozonetel正在利用ChatGPT來改善客戶體驗。該公司表示&#xff0c;他們通過使用ChatGPT收集與客戶互動過程收集的“語料”能夠更有針對性地提高服務效率&#xff0c;提供個性化的用戶體驗&#xff0c;并實現更高的客戶滿意度。[1] 通過這套解決方案&#xff0c;客服中心將擁有一…

javascript寫一個簡單的閉包例子

當你在JavaScript中創建一個閉包時&#xff0c;你可以將函數定義在另一個函數的內部&#xff0c;并從外部函數中返回該函數。以下是一個簡單的閉包示例&#xff1a; function outerFunction() {var outerVariable "I am from the outer function";function innerFu…

vue 圖片轉pdf

嘗試了集中圖片轉pdf的方式&#xff0c; &#xff08;1&#xff09;最終較為優秀的一種是使用jspdf將圖片轉為pdf&#xff0c;支持JPG/JPEG/PNG/BMP/TIF/TIFF圖片格式轉換&#xff0c;詳見我的另一篇文章&#xff1a; https://blog.csdn.net/Ann_52547/article/details/1322149…

MybatisPlus查詢結果返回值為null

1、問題描述 返回值為null&#xff0c;程序不報錯&#xff0c;但是條數好像是正確的。我出現問題的代碼如下&#xff1a; 1、自定義類StudentMapper繼承了BaseMapper接口 public interface StudentMapper extends BaseMapper<Student> { } 2、使用StudentMapper中的s…

centos 定時腳本檢測tomcat是否啟動,未啟動情況下重新啟動

編寫腳本 tomcatMonitor.sh #!/bin/sh. /etc/profile . ~/.bash_profile#首先用ps -ef | grep tomcat 獲得了tomcat進程信息&#xff0c;這樣出來的結果中會包含grep本身&#xff0c; #因此通過 | grep -v grep 來排除grep本身&#xff0c;然后通過 awk {print $2}來打印出要…