alex

alex

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  7 随笔 :: 6 文章 :: 7 评论 :: 0 Trackbacks

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
posted on 2007-02-11 15:52 agerlis 阅读(397) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理