在开发中经常要遇到需要将对象进行串行化(serialize)的情况,但c++语言或标准库目前并无直接的实现支持。同时由于c++本身的RTTI机制比较简单,功能有限,在面向对象编程时通过基类或接口指针进行串行化操作时更麻烦。本文是尝试解决该问题的一个实现。
程序中需要序列化的数据为对象Data及其派生类DataAnalog、DataDigital。架构中引入一个单件(Singleton)类DataFacotry,用于保存类信息与运行时的对象的动态创建。而类的具体创建则使用Prototype模式,便于扩充。类信息则通过C++的typeid获得。序列化的结果保存到一个json文本中,对json的读写使用了Qt的json类。
全部实现及测试代码如下:
1 #include <QCoreApplication> 2 3 #include <memory> 4 #include <vector> 5 #include <string> 6 #include <iostream> 7 #include <algorithm> 8 #include <QFile> 9 #include <QJsonDocument> 10 #include <QJsonObject> 11 #include <QJsonArray> 12 13 class Data 14 { 15 public: 16 Data(void){} 17 Data(const std::wstring &name) : dataName(name){} 18 virtual ~Data() {} 19 20 std::string getClassName(void){ 21 return typeid(*this).name(); 22 } 23 std::shared_ptr<Data> clone(void) const{ 24 auto data = newData(); 25 QJsonObject json; 26 write(json); 27 data->read(json); 28 return data; 29 } 30 31 std::wstring getName(void){ 32 return dataName; 33 } 34 35 virtual void write(QJsonObject &json) const{ 36 json["Name"] = QString::fromStdWString(dataName.c_str()); 37 38 } 39 virtual void read(const QJsonObject &json){ 40 dataName = json["Name"].toString().toStdWString(); 41 } 42 43 virtual void print(std::wostream &out){ 44 out << dataName.c_str() << std::endl; 45 } 46 47 protected: 48 virtual std::shared_ptr<Data> newData(void) const = 0; 49 50 private: 51 std::wstring dataName; 52 }; 53 54 class DataAnalog : public Data 55 { 56 public: 57 DataAnalog(void){} 58 DataAnalog(const std::wstring &name, const double value):Data(name), dataValue(value) {} 59 virtual ~DataAnalog(){} 60 61 virtual void write(QJsonObject &json) const override{ 62 Data::write(json); 63 json["Value"] = dataValue; 64 } 65 virtual void read(const QJsonObject &json) override{ 66 Data::read(json); 67 dataValue = json["Value"].toDouble(); 68 } 69 70 virtual void print(std::wostream &out){ 71 out << getName().c_str() << L"=" << dataValue << std::endl; 72 } 73 74 protected: 75 virtual std::shared_ptr<Data> newData(void) const override{ 76 return std::make_shared<DataAnalog>(); 77 } 78 79 private: 80 double dataValue = 0; 81 }; 82 83 class DataDigital : public Data 84 { 85 public: 86 DataDigital(void) {} 87 DataDigital(const std::wstring &name, const bool value):Data(name), dataValue(value){} 88 virtual ~DataDigital(){} 89 90 virtual void write(QJsonObject &json) const override{ 91 Data::write(json); 92 json["Value"] = dataValue; 93 } 94 virtual void read(const QJsonObject &json) override{ 95 Data::read(json); 96 dataValue = json["Value"].toBool(); 97 } 98 99 virtual void print(std::wostream &out) override{ 100 out << getName().c_str() << L"=" << (dataValue?L"true":L"false") << std::endl; 101 } 102 103 protected: 104 virtual std::shared_ptr<Data> newData(void) const override{ 105 return std::make_shared<DataAnalog>(); 106 } 107 108 private: 109 bool dataValue = false; 110 }; 111 112 class DataFacotry 113 { 114 public: 115 static DataFacotry& instance(void){ 116 static DataFacotry ins; 117 static bool initialized = false; 118 if(!initialized) 119 { 120 ins.registerPrototype(std::make_shared<DataAnalog>()); 121 ins.registerPrototype(std::make_shared<DataDigital>()); 122 initialized = true; 123 } 124 return ins; 125 } 126 127 void registerPrototype(std::shared_ptr<Data> protoType){ 128 prototypeDatas.emplace(protoType->getClassName(), protoType); 129 } 130 131 std::shared_ptr<Data> create(const std::string &className){ 132 auto it = prototypeDatas.find(className); 133 if(it!=prototypeDatas.end()){ 134 return it->second->clone(); 135 } 136 return nullptr; 137 } 138 139 private: 140 std::map<std::string, std::shared_ptr<Data>> prototypeDatas; 141 }; 142 143 int main(int argc, char *argv[]) 144 { 145 QCoreApplication a(argc, argv); 146 147 { 148 std::vector<std::shared_ptr<Data>> datas; 149 datas.emplace_back(new DataAnalog(L"Anlog_1", 1.1)); 150 datas.emplace_back(new DataAnalog(L"Anlog_2", 2.2)); 151 datas.emplace_back(new DataDigital(L"Digita_1", true)); 152 datas.emplace_back(new DataDigital(L"Digita_2", false)); 153 154 QFile file(QCoreApplication::applicationDirPath() + "\\data.json"); 155 if(file.open(QFile::WriteOnly)) 156 { 157 QJsonArray dataArray; 158 for(auto data:datas) 159 { 160 QJsonObject obj; 161 obj["Class"] = data->getClassName().c_str(); 162 QJsonObject dataObj; 163 data->write(dataObj); 164 obj["Data"] = dataObj; 165 dataArray.append(obj); 166 } 167 168 QJsonObject json; 169 json["Datas"] = dataArray; 170 QJsonDocument doc(json); 171 file.write(doc.toJson()); 172 } 173 } 174 175 { 176 QFile file(QCoreApplication::applicationDirPath() + "\\data.json"); 177 if(file.open(QFile::ReadOnly)) 178 { 179 QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); 180 if(!doc.isNull()) 181 { 182 QJsonObject json = doc.object(); 183 std::vector<std::shared_ptr<Data>> datas; 184 QJsonArray dataArray = json["Datas"].toArray(); 185 for(auto i : dataArray) 186 { 187 QJsonObject obj = i.toObject(); 188 QString className = obj["Class"].toString(); 189 auto data = DataFacotry::instance().create(className.toStdString()); 190 if(data) 191 { 192 datas.emplace_back(data); 193 datas.back()->read(obj["Data"].toObject()); 194 } 195 } 196 197 std::for_each(datas.begin(), datas.end() 198 , [](std::shared_ptr<Data> data){data->print(std::wcout);}); 199 200 } 201 } 202 } 203 204 return a.exec(); 205 }
发生