2013-07-15 75 views
2

我有一個提升序列化的小問題。有許多示例顯示如何通過簡單地使用BOOST_CLASS_EXPORT和BOOST_CLASS_EXPORT_IMPLEMENT來通過基類指針序列化派生類指針。這工作正常,沒有任何問題。通過取消引用的基類指針提升序列化

但是,我不想序列化一個指針,因爲另一端的反序列化應該再次通過一個指針,然後boost會創建一個新的序列化對象實例。

我可以序列化一個解除引用的指針,然後在沒有問題的情況下再次反序列化一個現有的對象實例,並且不會創建新的實例。但是,當解引用的指針位於基類之上時,派生類不會像序列化指針時那樣按序列化。

工作例如:

Class A; 
Class B : public A; 

A* baseClass = new B(); 
ar << baseClass // works perfectly 

不工作例如:

Class A; 
Class B : public A; 
A* baseClass = new B(); 
ar << *baseClass; // only A is serialized 

我可以得到它通過簡單的序列化在派生類中一樣工作:

B* derivedClass = new B(); 
ar << *derivedClass; // works fine 

但所有引用我在我的結構中有基類類型。另外,我不能序列化指針,因爲在反序列化時我不需要實例化新的objetcs,只需在現有實例上「覆蓋」內容。

我試圖序列化指針並試圖通過現有的實例反序列化,但這是行不通的。當我說反序列化在現有的情況下,我的意思是:

A* baseClass = new B(); 
// baseClass is used in the program and in a given moment, its contents must be overwrite, so: 
ar >> *baseClass; 

正如我所說的,反序列化時,我不需要基類的新實例。那麼,有什麼辦法可以使這個工作?

+0

嗨,有點晚了,但我剛剛發現了這個問題。我面臨着完全相同的問題......我認爲這個問題可以通過引用來解決,但是通過對基類的引用進行序列化並不適合我。你能解決這個問題嗎? – TomasG

+0

我終於使用了@TomasG指出的解決方案。基本上是在我想要以這種方式序列化的類中添加序列化和反序列化虛擬函數。幸運的是,他們很少。 –

+1

感謝回答,可惜沒有更優雅的解決方案。 – TomasG

回答

1

我遇到了同樣的問題!所以我查看了boost的文檔,它給出瞭解決問題的方法,我可以定義一個D類來管理派生對象,並使用ar.register_type來區分abc類,就像這樣:

class base { 
    ... 
}; 
class derived_one : public base { 
    ... 
}; 
class derived_two : public base { 
    ... 
}; 
main(){ 
    ... 
    base *b; 
    ... 
    ar & b; 
} 

當保存b就恰如樣的對象應該保存?何時加載b應該創建什麼樣的對象?它應該是類derived_one,derived_two或者base的對象嗎?

事實證明,序列化的對象的類型取決於基類(在本例中是基類)是否是多態的。如果base不是多態的,也就是說如果它沒有虛函數,那麼類型庫的一個對象將被序列化。任何派生類中的信息都將丟失。如果這是所期望的(通常不是),那麼不需要其他努力。

如果基類是多態的,則派生類型最大的對象(本例中爲derived_one或derived_two)將被序列化。圖書館自動處理(幾乎)由哪個類型的對象序列化的問題。

第一次將該類中的一個對象序列化併爲其分配序列號時,系統會將每個類「註冊」到檔案中。下一次,該類的對象將在同一個存檔中序列化,此編號將寫入存檔中。所以每個班級都在檔案中唯一標識。當讀回檔案時,每個新的序列號都與正在讀取的類重新關聯。請注意,這意味着「註冊」必須在保存和加載期間發生,以便構建在load上的類整數表與在save上構建的類整數表完全相同。事實上,整個系列化系統的關鍵在於事物總是以相同的順序保存和加載。這包括「註冊」。

main(){ 
    derived_one d1; 
    derived_two d2: 
    ... 
    ar & d1; 
    ar & d2; 
    // A side effect of serialization of objects d1 and d2 is that 
    // the classes derived_one and derived_two become known to the archive. 
    // So subsequent serialization of those classes by base pointer works 
    // without any special considerations. 
    base *b; 
    ... 
    ar & b; 
} 

當查看B它由唯一的(到存檔)先前已經與類derived_one或derived_two類標識符之前。

如果派生類沒有被如上所述自動「註冊」,則在調用序列化時將拋出unregistered_class異常。

這可以通過顯式註冊派生類來解決。所有檔案都從實現以下模板基類派生:

template<class T> 
register_type(); 

所以,我們的問題也可以同樣可以通過寫地址:

main(){ 
    ... 
    ar.template register_type<derived_one>(); 
    ar.template register_type<derived_two>(); 
    base *b; 
    ... 
    ar & b; 
} 

注意,如果序列化功能,保存之間的分裂和負載,這兩個函數都必須包含註冊。這需要保持同步中的保存和相應的負載。

你也可以使用:

#include <boost/serialization/export.hpp> 
... 
BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one") 
BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two") 

main(){ 
    ... 
    base *b; 
    ... 
    ar & b; 

} 宏BOOST_CLASS_EXPORT_GUID將字符串和類相關聯。在上面的例子中,我們使用了類名的字符串渲染。如果這種「已導出」類的對象通過指針序列化並且未註冊,則「導出」字符串將包含在歸檔中。稍後讀取存檔時,字符串文字將用於查找應該由序列化庫創建的類。這允許每個類都在一個單獨的頭文件中,以及它的字符串標識符。沒有必要對可能被序列化的派生類進行單獨的「預先註冊」。這種註冊方法被稱爲「密鑰輸出」。

也許對你有幫助!詳情你可以看到:http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html

+0

Thx爲您的答案,但它並沒有解決我的問題。 ar.register_type等於BOOST_CLASS_EXPORT,正如我在我的問題中提到的。這在序列化基類指針時起作用,但在序列化取消引用的基類指針時不起作用。在bus_route示例中,所有派生類都通過基類指針序列化(stop是bus_stop指針列表) –

1

我想我明白了這個問題。當你做

ar >> *DerivedClass; 

你傳遞一個參考operator<<。現在,通過引用基類訪問的對象沒有正確序列化,正如我從Robert Ramey對Boost-users郵件列表中的this question的回答中收集的。雖然答案已經有幾年了,但我認爲它仍然是正確的,因爲如果你想到的話,一個寫的方法不是虛擬的(它們是模板,所以它們是cannot be virtual)。

所以庫必須做特殊的東西來處理指針,但它並沒有用引用來做。一個醜陋的解決方案,我發現是添加一對(虛擬)序列化功能,如:

virtual myser(iarchive &ia) {ia >> *this;} 
virtual myser(oarchive &oa) {oa << *this;} 

其中iarchiveoarchive應當與你想要的檔案所取代。這真的很糟糕,因爲除了必須編寫兩個額外的函數之外,您必須明確地爲所有需要的歸檔類型重載它們。不幸的是我不知道更好的解決方案。

+0

只是我最後使用的方法...因爲沒有乾淨的解決方案。 –