在上一篇《Boost.Serialization 用基類指針轉存派生類》中,我們使用單一的 serialize 函數實現序列化。但實際上,該函數根據歸檔類型(保存或加載)會表現出不同行為:使用 xxx_oarchive 時等價於保存數據,使用 xxx_iarchive 時等價於加載數據。因此,我們可以將其拆分為獨立的 save 和 load 函數,從而獲得更精細的控制權,特別是處理版本升級時極為有用。
private:
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(name_);
ar & BOOST_SERIALIZATION_NVP(number_);
ar & BOOST_SERIALIZATION_NVP(grade_);
}
template<typename Archive>
void save(Archive& ar, const unsigned int version) const {
ar << BOOST_SERIALIZATION_NVP(name_);
ar << BOOST_SERIALIZATION_NVP(number_);
ar << BOOST_SERIALIZATION_NVP(grade_);
}
template<typename Archive>
void load(Archive& ar, const unsigned int version) {
ar >> BOOST_SERIALIZATION_NVP(name_);
ar >> BOOST_SERIALIZATION_NVP(number_);
ar >> BOOST_SERIALIZATION_NVP(grade_);
}
必須在類內部添加此宏,它實現了一個模板函數,內部調用 boost::serialization::split_member。該函數利用 traits 技術根據 Archive::is_saving 推導出 member_saver 或 member_loader 類型,進而調用我們定義的 save/load。這也是為什麼必須聲明 boost::serialization::access 為友元類的原因——它需要訪問私有的 save/load 成員函數。
class student_info {
public:
student_info() {}
virtual ~student_info() {}
student_info(const std::string& sn, const std::string& snm,
const std::string& sg, const std::string& cs)
: name_(sn), number_(snm), grade_(sg), class_(cs) {}
virtual void print_info() const {
std::cout << name_ << " " << number_ << " "
<< grade_ << " " << class_ << " ";
}
private:
friend class boost::serialization::access;
template<typename Archive>
void save(Archive& ar, const unsigned int version) const {
ar << BOOST_SERIALIZATION_NVP(name_);
ar << BOOST_SERIALIZATION_NVP(number_);
ar << BOOST_SERIALIZATION_NVP(grade_);
ar << BOOST_SERIALIZATION_NVP(class_);
}
template<typename Archive>
void load(Archive& ar, const unsigned int version) {
ar >> BOOST_SERIALIZATION_NVP(name_);
ar >> BOOST_SERIALIZATION_NVP(number_);
ar >> BOOST_SERIALIZATION_NVP(grade_);
}
BOOST_SERIALIZATION_SPLIT_MEMBER() // 必須在類內部
private:
std::string name_;
std::string number_;
std::string grade_;
std::string class_;
};
除了侵入式寫法,也可以採用非侵入式:在類外部定義 serialize 函數並聲明為友元,適合無法修改類定義的場景。