handle-body,睡死了,但还是得坚持下。其实这个是很简单的概念
这个也称呼为pimpl,是private implemention的缩写,下面涉及到的都叫做pimpl, 那用这个到底有什么好处呢:
1:可以把具体的实现从client端封装,这样即使修改实现,只要不修改头文件,对client端来说,是没有任何影响的,甚至不改变代码的2进制特性
2:加速编译时间,我们知道有时头文件有太多的实现,会导致包含这个头文件的其他文件的编译时间增加,通过pimpl,我们把实现从头文件移到cpp里面,从而减少了其他包含这个文件的编译时间,加快编译速度
3:减少依赖,这个实际上也增加了编译的速度,可以不对client端暴露一些实现上的头文件,从而减少了依赖说了这么多,下面来看下一个简单的pimpl的实现。是用loki的类来实现的。哈哈,睡死了,偷懒
/*.h*/
class CTest
{
public:
void Test();
private:
Loki::PimplT::Type m_impl;
};
------------------------------------------------------------------- /*.cpp*/
template<>
struct Loki::ImplT
{
public:
void Test() { std::cout << "test" << std::endl; }
};
void CTest::Test() { return m_impl->Test(); }
上面只是个很简单很简单的例子,以至于有些还无法体会到pimpl的作用,但相信在实践中你会体会到,把原来定义在CTest里面的一些私有的方法,成员,全部挪到ImplT里面时,你会体会到,这个CTest的头文件里include了很少的头,他可以说完成了原始的使命,达到了功能性接口的作用,而其他原来定义在头里的.h,可以全部挪到cpp里了。下面来分析下loki是怎么实现的。可以看到实现pimpl首先需要牵置声明pre define类,loki通过模板的全特化来实现了这个的隐藏,从而避免了把具体的实现类暴露给client的弊端。下面来看下这个泛化的pre define: template struct ImplT; 哈哈,很简单,再看上面我的cpp里的定义,大家结合上面也许就明白了吧,部过,这里需要注意的是,CTest的构造函数要写后面,不然can;t compile. 但是,为什么具体的实现类是ImplT但,前面的
Loki::PimplT::Type m_impl;
那Loki::PimplT::Type是什么用的,我们知道,假如保存原始的
Loki::ImplT<CTest>* m_impl;
然后new一个,其实这样只存在1个问题,2个不方便,
1:问题是这样的原始指针,不能传播const信息,也就是说,对象CTest转为const的化,他里面的指针类型不是同样随着带有const属性,也就是说,假如此时指针指向的对象有个函数,提供了const&none const的,此时,还是会调用non const的,所以,外界还是可以通过这个对象来做修改。
2:2个不方便是,你必须对对象实现new和delete.
下面来看下loki是怎么做的
template<class T>
struct ConstPropPtr
{
explicit ConstPropPtr(T* p) : ptr_(p) {}
~ConstPropPtr() { delete ptr_; ptr_ = 0; }
T* operator->() { return ptr_; }
T& operator*() { return *ptr_; }
const T* operator->() const { return ptr_; }
const T& operator*() const { return *ptr_; }
private:
ConstPropPtr();
ConstPropPtr(const ConstPropPtr&);
ConstPropPtr& operator=(const ConstPropPtr&);
T* ptr_;
};
这个类提供了对问题1的解决。下面会讲解,主要的点是,对象不同于指针,对象能传递const属性。
下面看下pimlT的定义:
template<class T, template<class> class Ptr = ConstPropPtr>
struct PimplT
{
typedef T Impl;
// declare pimpl
typedef Pimpl<ImplT<T>, Ptr<ImplT<T> > > Type;
// inherit pimpl
typedef PimplOwner<ImplT<T>, Ptr<ImplT<T> > > Owner;
};
可以看到对Type
的定义,下面的owner也不说了,直接到Pimpl,
template
<
class T,
typename Pointer = ConstPropPtr<T>
>
class Pimpl
{
public:
typedef T Impl;
Pimpl() : ptr_(new T)
{}
~Pimpl()
{
typedef char T_must_be_defined[sizeof(T) ? 1 : -1 ];
}
T* operator->()
{
return ptr_.operator->();
}
T& operator*()
{
return ptr_.operator*();
}
const T* operator->() const
{
return ptr_.operator->();
}
const T& operator*() const
{
return ptr_.operator*();
}
Pointer& wrapped()
{
return ptr_;
}
const Pointer& wrapped() const
{
return ptr_;
}
private:
Pimpl(const Pimpl&);
Pimpl& operator=(const Pimpl&);
Pointer ptr_;
};
可以看到,这个类用了上面的ConstPropPtr从而使对象有了const属性的传递。其他的,实际上,帮你操作了new,再ConstPropPtr里释放,有点RAII的味道,剩下的完全模拟保存的指针的行为,即implT的实现,从而使其能正确的操作对象。
睡死了,早早结束
alex_yuu