C++ 中多态对象串行化(Serialize)的一个实现方案


在开发中经常要遇到需要将对象进行串行化(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 }

发生


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM