demo_pimpl_A.hpp
// demo_pimpl_A.hpp
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// class whose declaration is hidden by a pointer
struct B;
struct A {
// class a contains a pointer to a "hidden" declaration
B *pimpl;
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version);
A();
~A();
};
#endif // BOOST_SERIALIZATION_EXAMPLE_DEMO_PIMPL_A_HPP
在这段文本中,有一个名为demo_pimpl.cpp的程序,用来演示如何使用PIMPL。文件demo_pimpl_A.hpp包含了一个类A的声明,该类通过包含一个指向结构体B的指针来隐藏其实现细节。但是,B的具体定义在另一个单独编译的模块demo_pimpl_A.cpp中。
demo_pimpl_A.cpp
// demo_pimpl_A.cpp
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "demo_pimpl_A.hpp"
// "hidden" definition of class B
struct B {
int b;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
ar & b;
}
};
A::A() :
pimpl(new B)
{}
A::~A(){
delete pimpl;
}
// now we can define the serialization for class A
template<class Archive>
void A::serialize(Archive & ar, const unsigned int /* file_version */){
ar & pimpl;
}
这种设计的优势包括:
1.类型B可以在不包含其头文件的情况下使用。
2.类型B的实现可以更改而不会引发大规模的重新编译。
然而,在链接时,会出现错误,因为两个符号未定义:
void A::serialize(boost::archive::text_oarchive & ar, const unsigned int file_version);
void A::serialize(boost::archive::text_iarchive & ar, const unsigned int file_version);
问题在于,在编译上述代码时,serialize模板没有被实例化,因为不知道要与哪种类型的归档一起使用。因此,在尝试链接时,这些函数会“丢失”。解决方法是显式实例化将要使用的归档类型的序列化代码。在示例中,通过在任何*.cpp文件中包含以下代码来实现:
// without the explicit instantiations below, the program will
// fail to link for lack of instantiantiation of the above function
// note: the following failed to fix link errors for vc 7.0 !
template void A::serialize<boost::archive::text_iarchive>(
boost::archive::text_iarchive & ar,
const unsigned int file_version
);
template void A::serialize<boost::archive::text_oarchive>(
boost::archive::text_oarchive & ar,
const unsigned int file_version
);
这样,程序就能够成功链接。不过,这种方法的缺点是必须事先知道要与隐藏的序列化一起使用哪些归档类型,因为它依赖于显式实例化模板,而这可能会导致平台依赖性。
demo_pimpl.cpp
// demo_pimpl.cpp
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "demo_pimpl_A.hpp"
int main(int argc, char* argv[])
{
std::stringstream ss;
const A a;
{
boost::archive::text_oarchive oa(ss);
oa << a;
}
A a1;
{
boost::archive::text_iarchive ia(ss);
ia >> a1;
}
return 0;
}