Câu trả lời của Yacoby có thể được mở rộng thêm.
Tôi tin rằng việc tuần tự hóa có thể được triển khai theo cách tương tự như ngôn ngữ được quản lý nếu thực sự thực hiện một hệ thống phản chiếu.
Trong nhiều năm, chúng tôi đã sử dụng phương pháp tự động.
Tôi là một trong những người triển khai bộ xử lý C++ hoạt động và thư viện Reflection: công cụ LSDC và Linderdaum Engine Core (iObject + RTTI + Linker/Loader). Xem nguồn tại số http://www.linderdaum.com
Nhà máy lớp tóm tắt quá trình khởi tạo lớp.
Để khởi tạo các thành viên cụ thể, bạn có thể thêm một số RTTI xâm nhập và tự động tạo các quy trình tải/lưu cho chúng.
Giả sử bạn có lớp iObject ở đầu hệ thống phân cấp của mình.
// Base class with intrusive RTTI
class iObject
{
public:
iMetaClass* FMetaClass;
};
///The iMetaClass stores the list of properties and provides the Construct() method:
// List of properties
class iMetaClass: public iObject
{
public:
virtual iObject* Construct() const = 0;
/// List of all the properties (excluding the ones from base class)
vector<iProperty*> FProperties;
/// Support the hierarchy
iMetaClass* FSuperClass;
/// Name of the class
string FName;
};
// The NativeMetaClass<T> template implements the Construct() method.
template <class T> class NativeMetaClass: public iMetaClass
{
public:
virtual iObject* Construct() const
{
iObject* Res = new T();
Res->FMetaClass = this;
return Res;
}
};
// mlNode is the representation of the markup language: xml, json or whatever else.
// The hierarchy might have come from the XML file or JSON or some custom script
class mlNode {
public:
string FName;
string FValue;
vector<mlNode*> FChildren;
};
class iProperty: public iObject {
public:
/// Load the property from internal tree representation
virtual void Load(iObject* TheObject, mlNode* Node) const = 0;
/// Serialize the property to some internal representation
virtual mlNode* Save(iObject* TheObject) const = 0;
};
/// function to save a single field
typedef mlNode* (*SaveFunction_t)(iObject* Obj);
/// function to load a single field from mlNode
typedef void (*LoadFunction_t)(mlNode* Node, iObject* Obj);
// The implementation for a scalar/iObject field
// The array-based property requires somewhat different implementation
// Load/Save functions are autogenerated by some tool.
class clFieldProperty : public iProperty {
public:
clFieldProperty() {}
virtual ~clFieldProperty() {}
/// Load single field of an object
virtual void Load(iObject* TheObject, mlNode* Node) const {
FLoadFunction(TheObject, Node);
}
/// Save single field of an object
virtual mlNode* Save(iObject* TheObject, mlNode** Result) const {
return FSaveFunction(TheObject);
}
public:
// these pointers are set in property registration code
LoadFunction_t FLoadFunction;
SaveFunction_t FSaveFunction;
};
// The Loader class stores the list of metaclasses
class Loader: public iObject {
public:
void RegisterMetaclass(iMetaClass* C) { FClasses[C->FName] = C; }
iObject* CreateByName(const string& ClassName) { return FClasses[ClassName]->Construct(); }
/// The implementation is an almost trivial iteration of all the properties
/// in the metaclass and calling the iProperty's Load/Save methods for each field
void LoadFromNode(mlNode* Source, iObject** Result);
/// Create the tree-based representation of the object
mlNode* Save(iObject* Source);
map<string, iMetaClass*> FClasses;
};
Khi bạn xác định ConcreteClass bắt nguồn từ iObject, bạn sử dụng một số tiện ích mở rộng và công cụ tạo mã để tạo danh sách quy trình lưu/tải và mã đăng ký.
Hãy để chúng tôi xem mã cho mẫu này.
Một nơi nào đó trong khuôn khổ chúng ta có một sản phẩm nào chính thức xác định
#define PROPERTY(...)
/// vec3 is a custom type with implementation omitted for brevity
/// ConcreteClass2 is also omitted
class ConcreteClass: public iObject {
public:
ConcreteClass(): FInt(10), FString("Default") {}
/// Inform the tool about our properties
PROPERTY(Name=Int, Type=int, FieldName=FInt)
/// We can also provide get/set accessors
PROPERTY(Name=Int, Type=vec3, Getter=GetPos, Setter=SetPos)
/// And the other field
PROPERTY(Name=Str, Type=string, FieldName=FString)
/// And the embedded object
PROPERTY(Name=Embedded, Type=ConcreteClass2, FieldName=FEmbedded)
/// public field
int FInt;
/// public field
string FString;
/// public embedded object
ConcreteClass2* FEmbedded;
/// Getter
vec3 GetPos() const { return FPos; }
/// Setter
void SetPos(const vec3& Pos) { FPos = Pos; }
private:
vec3 FPos;
};
Mã đăng ký autogenerated sẽ là:
/// Call this to add everything to the linker
void Register_ConcreteClass(Linker* L) {
iMetaClass* C = new NativeMetaClass<ConcreteClass>();
C->FName = "ConcreteClass";
iProperty* P;
P = new FieldProperty();
P->FName = "Int";
P->FLoadFunction = &Load_ConcreteClass_FInt_Field;
P->FSaveFunction = &Save_ConcreteClass_FInt_Field;
C->FProperties.push_back(P);
... same for FString and GetPos/SetPos
C->FSuperClass = L->FClasses["iObject"];
L->RegisterClass(C);
}
// The autogenerated loaders (no error checking for brevity):
void Load_ConcreteClass_FInt_Field(iObject* Dest, mlNode* Val) {
dynamic_cast<ConcereteClass*>Object->FInt = Str2Int(Val->FValue);
}
mlNode* Save_ConcreteClass_FInt_Field(iObject* Dest, mlNode* Val) {
mlNode* Res = new mlNode();
Res->FValue = Int2Str(dynamic_cast<ConcereteClass*>Object->FInt);
return Res;
}
/// similar code for FString and GetPos/SetPos pair with obvious changes
Bây giờ, nếu bạn có kịch bản thứ bậc JSON như
Object("ConcreteClass") {
Int 50
Str 10
Pos 1.5 2.2 3.3
Embedded("ConcreteClass2") {
SomeProp Value
}
}
Đối tượng Trình liên kết sẽ giải quyết tất cả các lớp và thuộc tính trong Lưu/Tải phương pháp.
Xin lỗi vì bài đăng dài, triển khai sẽ phát triển lớn hơn nữa khi tất cả xử lý lỗi đến.
@SergeyK: những thay đổi gần đây? Tôi chắc chắn không nghe nói về bất kỳ. –
Ý tôi là câu trả lời này: http://stackoverflow.com/a/10332336/1065190 –
@SergeyK .: Ah! Tôi nghĩ rằng phần bình luận trên chính câu trả lời có lẽ là nơi tốt nhất để thảo luận về nó. Trong thực tế, tôi đã bắt đầu. Nó có vẻ khá bí truyền đối với tôi, đặc biệt là ý tưởng sáp nhập serialization với getters tự động và setters (nó thường là xấu để kết hợp các khái niệm khác nhau). Cũng nhắc tôi về một dự án QT nào đó ... cuối cùng, bạn có bán C++ và bạn mất tính di động vì bạn phụ thuộc vào khả năng sẵn có của công cụ được cho là biến nó thành đúng C++. Tôi không giữ được hơi thở. –