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

          導航

          留言簿(1)

          隨筆分類(31)

          文章分類(4)

          收藏夾(21)

          搜索

          •  

          積分與排名

          • 積分 - 29910
          • 排名 - 1389

          最新隨筆

          最新評論

          閱讀排行榜

           
          在讀《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 閱讀(917) 評論(0)  編輯  收藏 所屬分類: C++
           
          Copyright © Dest Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 石河子市| 白河县| 丹江口市| 吉林省| 肥城市| 丁青县| 文昌市| 扎兰屯市| 垫江县| 东台市| 永善县| 阜新市| 涪陵区| 贵德县| 葵青区| 绥德县| 峨眉山市| 金昌市| 罗平县| 厦门市| 庄河市| 葫芦岛市| 元氏县| 鄄城县| 贵德县| 龙门县| 苏尼特右旗| 仪征市| 丹巴县| 瑞安市| 莫力| 安陆市| 昌平区| 堆龙德庆县| 南安市| 赤壁市| 蒲江县| 城固县| 和田县| 孙吴县| 临桂县|