編輯:新的答案下面添加以解決實際問題。
你的問題意味着你反序列化爲同一個對象。如果那是乾淨的或不乾淨的情況。例如,如果你有一個國際象棋棋盤,你會想要 同步棋子的初始位置(從上次保存的遊戲繼續)。爲了在遊戲進行時傳達這些動作,將個別移動 作爲單獨的對象發送(然後將其應用於一旦接收到板對象)可能是更好的主意,而不是傳送整個板對象,其將僅傳送具有如果它已經「初始化」就更改。 通過這種方式,您可以先驗證輸入並忽略無效移動。無論如何,我只想提一提,讓我們繼續前進。
如果您有一個對象可能被多次同步,並且只需要傳輸一次成員數據,讓對象決定它是否被「初始化」(並且因此,如果它需要傳輸所有內容或只是一個子集)通過使用一個標誌(這是不序列化)。
然後,您可以檢查對象序列化代碼中的標誌,就像在您發佈的代碼中一樣(除了該標誌不是序列化方法的參數 ,而是對象的成員變量德/序列化)。如果該標誌已設置,則將所有內容解除/序列化並重置該標誌。客戶端和服務器都必須具有相同的標誌狀態,否則序列化會中斷。
或者,您可以先序列化標記,告訴接收器如何執行反序列化(例如,每個成員數據組一個位)。
請記住,反序列化必須與序列化相匹配;您必須按照序列化的順序提取相同的對象。
但是,您可以序列化多態類,因爲它們在類層次結構中被序列化,因爲它們是反序列化的 (如果有疑問,當通過基指針發送和反序列化時將其轉換爲基指針)。
關於你的第二個問題,你要找的是non-intrusive serialization。 非侵入式序列化調用獨立函數並將要被序列化的對象作爲參數傳遞(std :: vector和boost :: shared_ptr是如何被序列化的)。 您可以使用BOOST_SERIALIZATION_SPLIT_FREE
將獨立功能serialize()
功能拆分爲save()
和load()
。對於侵入式序列化,它是BOOST_SERIALIZATION_SPLIT_MEMBER
。
要編寫一個廣義德/序列化功能(即通過網絡例如發送對象),你可以使用模板:
template<typename T>
void transmit(const T& data) {
// ...
archive << data
socket << archive_stream;
}
這種方法的限制是,接收機必須知道什麼樣的對象寄了,送了。如果你想發送的隨機對象,讓他們多態:
IData* data = 0;
archive >> data;
switch(data->type()) {
case TYPE_INIT:
return dispatch(static_cast<Board*>(data));
case TYPE_MOVE:
return dispatch(static_cast<Move*>(data));
case TYPE_CHAT:
return dispatch(static_cast<ChatMsg*>(data));
}
UPDATE:如果你需要控制你的(自定義)的序列化方法/功能的行爲,基於未知類型的狀態被序列化,你可以實現你自己的檔案類,它保存狀態。序列化函數然後可以查詢狀態並相應地採取行動。
此狀態(或適當的替代)也必須序列化以指示數據如何反序列化。例如,序列化函數的這種「不同行爲」可能是某種壓縮,而狀態是使用的壓縮類型。
下面是一個自定義輸出存檔的簡單示例。欲瞭解更多信息,您可以閱讀Derivation from an Existing Archive並挖掘助推源。
給出一個類,你不能修改:
struct Foo {
Foo() : i(42), s("foo") {}
int i;
std::string s;
};
你希望基於未知的類條件序列化i
和/或s
。你可以創建一個包裝器來序列化它並添加狀態,但如果對象位於向量(或其他類)中,則這不起作用。
可能更容易使存檔知道狀態,而不是:
#include <boost/archive/text_oarchive.hpp>
// using struct to omit a bunch of friend declarations
struct oarchive : boost::archive::text_oarchive_impl<oarchive>
{
oarchive(std::ostream& os, unsigned flags=0)
: boost::archive::text_oarchive_impl<oarchive>(os,flags),mask(0){}
// forward to base class
template<class T> void save(T& t) {
boost::archive::text_oarchive_impl<oarchive>::save(t);
}
// this is the 'state' that can be set on the archive
// and queried by the serialization functions
unsigned get_mask() const { return mask; }
void set_mask(unsigned m) { mask = m; }
void clear_mask() { mask = 0; }
private:
unsigned mask;
};
// explicit instantiation of class templates involved
namespace boost { namespace archive {
template class basic_text_oarchive<oarchive>;
template class text_oarchive_impl<oarchive>;
template class detail::archive_serializer_map<oarchive>;
} }
// template implementations (should go to the .cpp)
#include <boost/archive/impl/basic_text_oarchive.ipp>
#include <boost/archive/impl/text_oarchive_impl.ipp>
#include <boost/archive/impl/archive_serializer_map.ipp>
我們設置狀態和查詢:
enum state { FULL=0x10, PARTIAL=0x20 };
,並設置狀態的方法(這是隻是一個非常基本的例子):
oarchive& operator<<(oarchive& ar, state mask) {
ar.set_mask(ar.get_mask()|mask);
return ar;
}
最後,(非侵入式)序列化函數:
namespace boost { namespace serialization {
template<class Archive>
void save(Archive & ar, const Foo& foo, const unsigned int version)
{
int mask = ar.get_mask(); // get state from the archive
ar << mask; // serialize the state! when deserializing,
// read the state first and extract the data accordingly
if(mask & FULL)
ar << foo.s; // only serialize s if FULL is set
ar << foo.i; // otherwise serialize i only
ar.clear_mask(); // reset the state
}
} } // boost::serialization
BOOST_SERIALIZATION_SPLIT_FREE(Foo)
並且這可以使用如下:
int main() {
std::stringstream strm;
oarchive ar(strm);
Foo f;
ar << PARTIAL << f << FULL << f;
std::cout << strm.str();
}
本實施例的目的僅僅是說明原理。生產代碼太基本了。
我有加速的問題是,我必須序列化類的成員,我想在某些情況下,做的是序列化類的唯一部分,可能甚至不是成員變量的部分,而是從成員變量的一部分構建的數據。我不會每次完全序列化所有數據,我只會序列化所需的數據以確定發生了什麼變化。只有初始序列化將包含所有數據。 –
根據我的整體需求,我決定不使用Boost序列化。大多數情況下,我只是想要一個能夠將常見數據類型序列化爲二進制/從二進制序列化的庫,但提升的方式並不完全符合我的要求。我可能會寫我自己的方法來將類型轉換爲/從二進制文件,並使用一個單獨的庫來壓縮/解壓縮比特流。儘管你的回答基於我的問題接近我所需要的,所以我會將其標記爲我的問題的答案。謝謝。 –
@NicFoster自從我誤解了你的問題之後,我即將刪除答案。在我(或其他人)提出正確的解決方案之前,請隨時不接受並取消其評論。你想序列化一個你不能修改的類(例如)一個向量,並且你想控制如何序列化它而不會回覆到一個全局變量。 –