[导入]pImpl Idiom

[导入]pImpl Idiom
在读《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


CodeLoser 2010-08-07 22:58 发表评论

文章来源: http://www.blogjava.net/wenhl5656/archive/2010/08/07/328217.html

你可能感兴趣的:([导入]pImpl Idiom)