PIMPL IDIOM
来源:互联网 发布:知乎 正常感情浓度 编辑:程序博客网 时间:2024/04/24 04:05
“One popular technique is called the Pimpl idiom. This involves isolating all of a class’s private data members inside of a separate implementation class or struct in the .cpp file. The .h file then only needs to contain an opaque pointer to this implementation class.”
一 简介
今天阅读《C++ API设计》一书,设计到了PIMPL IDIOM,于是研究了一下。
PIMPL IDIOM是由JeffSumner首次提出的概念,意为“pointertoimplementation”,即指向实现的指针。这是一种用来隐藏源代码头文件实现细节的方法,可以保持API接口与实现的高度分离。严格来说PIMPL并不是一种设计模式,而只是一个术语,可以当作桥接模式的一个特例。
二 使用PIMPL
PIMPL基于这样一个事实:在C++类中,允许定义一个成员指针,指向一个已声明过的类型。在头文件中只是存放该类型的声明,而具体的定义是存放在CPP文件中,这样就可以隐藏类型的具体实现。
下图截取自《C++API设计》:
下面的例子展示了PIMPL的用法。AutoTimer是一个C++类,其作用是在对象被销毁时,打印出该对想的生存时间:
- //autotimer.h
- #ifdef_WIN32
- #include<windows.h>
- #else
- #include<sys/time.h>
- #endif
- #include<string>
- classAutoTimer
- {
- public:
- ///Create a new timer object with a human-readable name
- explicitAutoTimer(const std::string &name);
- ///On destruction, the timer reports how long it was alive
- ~AutoTimer();
- private:
- //Return how long the object has been alive
- doubleGetElapsed() const;
- std::stringmName;
- #ifdef_WIN32
- DWORDmStartTime;
- #else
- structtimeval mStartTime;
- #endif
- };
//autotimer.h#ifdef_WIN32#include<windows.h>#else#include<sys/time.h>#endif#include<string>classAutoTimer{public:///Create a new timer object with a human-readable nameexplicitAutoTimer(const std::string &name);///On destruction, the timer reports how long it was alive~AutoTimer();private://Return how long the object has been alivedoubleGetElapsed() const;std::stringmName;#ifdef_WIN32DWORDmStartTime;#elsestructtimeval mStartTime;#endif};
很明显,这个类设计的并不好,它违反了很多优秀API设计的准则。首先,它包含了平台相关的定义;其次,它暴露了底层的具体实现,不同平台是如何存储的具体细节。
我们的目的很明确,就是隐藏具体实现细节,只将公开接口暴露出来。此时PIMPL闪亮登场,我们可以将具体细节放在PIMPL指向的类型中,将该类型的定义放在CPP文件中,用户将不会看到CPP文件。重构后的头文件代码如下:
- //autotimer.h
- #include<string>
- classAutoTimer
- {
- public:
- explicitAutoTimer(const std::string &name);
- ~AutoTimer();
- private:
- classImpl;//嵌套类
- Impl*mImpl;//PIMPL指针
- };
//autotimer.h#include<string>classAutoTimer{public:explicitAutoTimer(const std::string &name);~AutoTimer();private:classImpl;//嵌套类Impl*mImpl;//PIMPL指针};
可以看出,我们声明了一个Impl类型,并定义了一个指向该类型的指针mImpl;但该类型的定义我们并不能看到,因为其定义放在CPP文件中了。接下来我们看CPP文件:
- //autotimer.cpp
- #include"autotimer.h"
- #include<iostream>
- #if_WIN32
- #include<windows.h>
- #else
- #include<sys/time.h>
- #endif
- classAutoTimer::Impl
- {
- public:
- doubleGetElapsed() const
- {
- #ifdef_WIN32
- return(GetTickCount() - mStartTime) / 1e3;
- #else
- structtimeval end_time;
- gettimeofday(&end_time,NULL);
- doublet1 1⁄4 mStartTime.tv_usec / 1e6 þ mStartTime.tv_sec;
- doublet2 1⁄4 end_time.tv_usec / 1e6 þ end_time.tv_sec;
- returnt2 - t1;
- #endif
- }
- std::stringmName;
- #ifdef_WIN32
- DWORDmStartTime;
- #else
- structtimeval mStartTime;
- #endif
- };
- AutoTimer::AutoTimer(conststd::string &name) :
- mImpl(newAutoTimer::Impl())
- {
- mImpl->mName1⁄4 name;
- #ifdef_WIN32
- mImpl->mStartTime1⁄4 GetTickCount();
- #else
- gettimeofday(&mImpl->mStartTime,NULL);
- #endif
- }
- AutoTimer::AutoTimer()
- {
- std::cout<< mImpl->mName << ": took " <<mImpl->GetElapsed()
- <<" secs" << std::endl;
- deletemImpl;
- mImpl= NULL;
- }
//autotimer.cpp#include"autotimer.h"#include<iostream>#if_WIN32#include<windows.h>#else#include<sys/time.h>#endifclassAutoTimer::Impl{public:doubleGetElapsed() const{#ifdef_WIN32return(GetTickCount() - mStartTime) / 1e3;#elsestructtimeval end_time;gettimeofday(&end_time,NULL);doublet1 1⁄4 mStartTime.tv_usec / 1e6 þ mStartTime.tv_sec;doublet2 1⁄4 end_time.tv_usec / 1e6 þ end_time.tv_sec;returnt2 - t1;#endif}std::stringmName;#ifdef_WIN32DWORDmStartTime;#elsestructtimeval mStartTime;#endif};AutoTimer::AutoTimer(conststd::string &name) :mImpl(newAutoTimer::Impl()){mImpl->mName1⁄4 name;#ifdef_WIN32mImpl->mStartTime1⁄4 GetTickCount();#elsegettimeofday(&mImpl->mStartTime,NULL);#endif}AutoTimer::AutoTimer(){std::cout<< mImpl->mName << ": took " <<mImpl->GetElapsed()<<" secs" << std::endl;deletemImpl;mImpl= NULL;}
从CPP文件中,我们但到了Impl类的具体定义,其包含了平台相关的代码,以及底层如何存储的细节。
在头文件中,我们声明Impl类为一个私有的嵌套类型,这是有好处的。声明为嵌套类不会污染全局的命名空间,而私有类型确保只有AutoTimer类的成员能够使用该类型,其他类无法访问。
- PIMPL IDIOM
- pimpl idiom
- Pimpl idiom
- PIMPL IDIOM & FAST PIMPL
- PIMPL IDIOM & FAST PIMPL
- PIMPL IDIOM & FAST PIMPL
- Pimpl idiom & fast Pimpl
- The "Fast Pimpl" Idiom
- PIMPL IDIOM简介
- The Fast Pimpl Idiom
- pimpl idiom in c++
- Item 30. The "Fast Pimpl" Idiom
- 关于PIMPL IDIOM(Opaque Pointer)
- C++实现设计模式: PIMPL IDIOM
- cheshire cat/pimpl idiom & Guru of the Week 条款28:“Fast Pimpl”技术
- idiom
- Pimpl idiom,前向声明(forward declaration)与#include头文件
- pimpl
- 汽车电子相关总结
- hiveQL 外部表
- 4.5 CMMI4级——4级执行过程中的五个疑问及解答
- lua闭包简介
- 使用CFileFind遍历递归删除文件和文件夹
- PIMPL IDIOM
- 第十一周
- POJ 2774
- JAVA基础__语法1
- windows高级隐藏
- B树索引
- ubuntu 13.10编译tolua++
- spring 的 applicationcontext.xml
- 每个Linux用户必知的省时技巧