LALA  
日历
<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

留言簿(1)

随笔分类(31)

文章分类(4)

收藏夹(21)

搜索

  •  

积分与排名

  • 积分 - 29318
  • 排名 - 1400

最新随笔

最新评论

阅读排行榜

 
在读《Effective C++》和项目源代码时,看到pImpl Idiom。它可以用来降低文件间的编译依赖关系,通过把一个Class分成两个Class,一个只提供接口,另一个负责实现该接口,实现接口与实现的分离。这个分离的关键在于“以声明的依赖性”替换“定义的依赖性”,而编译依赖性最小化的本质是:让头文件尽可能的自我满足,万一做不到,则让它与其他文件内的声明式(而非定义式)相依。

引用这里的一些描述:
The Pimpl idiom, also known as the compilation firewall or Cheshire Cat technique, is a "private implementation" technique useful only in CeePlusPlus and statically compiled languages like it...

Benefits:
  1. Changing private member variables of a class does not require recompiling classes that depend on it, thus make times are faster, and the FragileBinaryInterfaceProblem is reduced.
  2. The header file does not need to #include classes that are used 'by value' in private member variables, thus compile times are faster.
  3. This is sorta like the way SmallTalk automatically handles classes... more pure encapsulation.
Drawbacks:
  1. More work for the implementor.
  2. Doesn't work for 'protected' members where access by subclasses is required.
  3. Somewhat harder to read code, since some information is no longer in the header file.
  4. Run-time performance is slightly compromised due to the pointer indirection, especially if function calls are virtual (branch prediction for indirect branches is generally poor).
How to do it:
  1. Put all the private member variables into a struct.
  2. Put the struct definition in the .cpp file.
  3. In the header file, put only the ForwardDeclaration of the struct.
  4. In the class definition, declare a (smart) pointer to the struct as the only private member variable.
  5. The constructors for the class need to create the struct.
  6. The destructor of the class needs to destroy the struct (possibly implicitly due to use of a smart pointer).
  7. The assignment operator and CopyConstructor need to copy the struct appropriately or else be disabled.
Code:
1   struct AImp;
2   class A {
3   public:
4     // Same public interface as A, but all delegated to concrete implementation.
5   private:
6     AImp * pimpl;
7   };
8 


If you use a SmartPointer and you only have one implementation, there is no need to make any of the member functions virtual, except possibly the destructor. The run-time cost of non-virtual member function calls is much lower, and a compiler that does whole-program optimization can inline them even though they're in a separate translation unit. Here's an example:
 1  // foo.h
 2 
 3   class foo_impl;
 4 
 5   class foo {
 6     // Boilerplate
 7     friend class foo_impl;
 8     foo() {} // so only foo_impl can derive from foo
 9     const foo_impl * impl() const;
10     foo_impl * impl();
11   public:
12     virtual ~foo() {}
13     // Factories
14     static std::auto_ptr<foo> create(int value);
15     // Interface
16     int value() const;
17   };
18 
19   // foo.cpp
20 
21   class foo_impl : public foo {
22     friend class foo;
23     // Constructors mirroring the factory functions in foo
24     explicit foo_impl(int value) : value_(value) {}
25     // Member data
26     int value_;
27   };
28 
29   inline const foo_impl * foo::impl() const {
30     return static_cast<const foo_impl *>(this);
31   }
32   inline foo_impl * foo::impl() {
33     return static_cast<foo_impl *>(this);
34   }
35 
36   std::auto_ptr<foo> foo::create(int value) {
37     return std::auto_ptr<foo>(new foo_impl(value));
38   }
39 
40   int foo::value() const { return impl()->value_; }
41 
42 

Here, the destructor needs to be declared virtual foo so that std::auto_ptr<foo> calls foo_impl's destructor. If you use boost::shared_ptr<foo> instead, even that doesn't need to be virtual, because shared_ptr remembers how to call the correct destructor. (This doesn't improve performance or memory use, because shared_ptr is larger and slower than auto_ptr, but if you need to use shared_ptr anyway you may as well eliminate the virtual destructor.) -- BenHutchings


参考阅读:

Effective C++
http://c2.com/cgi/wiki?PimplIdiom
http://en.wikipedia.org/wiki/Opaque_pointer
posted on 2010-08-07 22:58 Dest 阅读(902) 评论(0)  编辑  收藏 所属分类: C++
 
Copyright © Dest Powered by: 博客园 模板提供:沪江博客