当前位置:网站首页>API Design Notes: The pimpl trick
API Design Notes: The pimpl trick
2022-08-01 04:26:00 【Pick up cues】
pimpl
pointer to implementation:指向实现的指针,Use this trick to avoid exposing private details in header files,可以促进APIInterface and implementation remain completely separate.

PimplA data member of a class can be defined as a pointer to a declared type,这里的类型仅仅作为名字引入,not fully defined,So we can hide the type definition in .cpp中,This is called an opaque pointer.
Below is an automatic timerAPI,Will print its lifetime when destroyed.
原有api
// autotimer.h
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <string>
class AutoTimer
{
public:
// Create new timers with easy-to-understand names
explicit AutoTimer(const std::string& name); // xplicitAvoid implicit construction, Only through display(explicit)构造.
// The timer reports the time-to-live on destruction
~AutoTimer();
private:
// Returns how long the object has been around
double GetElapsed() const;
std::string mName;
#ifdef _WIN32
DWORD mStartTime;
#else
struct timeval mStartTime;
#endif
};
这个APIThe design contains several disadvantages as follows:
1、Contains platform-specific definitions
2、Exposes the low-level details of how timers are stored on different platforms
3、Declare private members in public header files.(这是C++要求的)
The designer's real intention is to hide all private members.cpp文件中,这样我们可以使用Pimpl惯用法了.
Put all private members in an implementation class,这个类在头文件中前置声明,在.cpp中定义,下面是效果:
autotimer.h
// autotimer.h
#include <string.h>
class AutoTimer {
public:
explicit AutoTimer(const std::string& name);
~AutoTimer();
private:
class Impl;
Impl* mImpl;
};
Constructor requires allocationAutoTimer::Impltype variable and destroyed in the destructor.
All private members must passmImpl指针访问.
autotimer.cpp
// autotimer.cpp
#include "autotimer.h"
#include <iostream>
#if _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
class AutoTimer::Impl
{
public:
double GetElapsed() const
{
#ifdef _WIN32
return (GetTickCount() - mStartTime) / 1e3;
#else
struct timeval end_time;
gettimeofday(&end_time, NULL);
double t1 = mStartTime.tv_usec / 1e6 + mStartTime.tv_sec;
double t2 = end_time.tv_usec / 1e6 + end_time.tv_sec;
return t2 - t1;
#endif
}
std::string mName;
#ifdef _WIN32
DWORD mStartTime;
#else
struct timeval mStartTime;
#endif
};
AutoTimer::AutoTimer(const std::string& name) : mImpl(new AutoTimer::Impl())
{
mImpl->mName = name;
#ifdef _WIN32
mImpl->mStartTime = GetTickCount();
#else
gettimeofday(&mImpl->mStartTime, NULL);
#endif
}
AutoTimer::~AutoTimer()
{
std::cout << mImpl->mName << ":took" << mImpl->GetElapsed()
<< " secs" << std::endl;
delete mImpl;
mImpl = NULL;
}
ImplThe definition of contains all private methods and variables exposed in the original header file.
AutoTimer's constructor allocates a new oneAutoTimer::Implobject and initialize its members,The destructor is responsible for destroying the object.
Impl类为AutoTimer的私有内嵌类,如果想让.cppOther classes or free function access in the fileImplIf so, it can be declared as a public class.
// autotimer.h
#include <string.h>
class AutoTimer {
public:
explicit AutoTimer(const std::string& name);
~AutoTimer();
class Impl;
private:
Impl* mImpl;
};
如何规划Impl类中的逻辑?
Generally place all private members and private methods in Impl类中,You can avoid declaring private methods in public header files.
注意事项:
不能在ImplHide private virtual functions in the class,Virtual functions must appear in public classes,This ensures that any derived class can override them
pimpl的复制语义
在c++中,If no copy constructor and assignment operator are explicitly defined for the class,C++The compiler will create it by default,But this default function can only perform a shallow copy of the object,This is not good for classes that have pointer members in the class.
If the client copied the object,Then the two object pointers will point to the same oneImpl对象,Two objects may try to delete the same object twice in the destructor resulting in a crash.
Two solutions are provided below:
1、禁止复制类,Objects can be declared non-copyable
2、Explicitly define copy semantics
#include <string>
class AutoTimer
{
public:
explicit AutoTimer(const std::string& name);
~AutoTimer();
private:
AutoTimer(const AutoTimer&);
const AutoTimer &operator=(const AutoTimer&);
class Impl;
Impl* mImpl;
}
Smart pointer optimizationPimpl
Optimize object deletion with the help of smart pointers,Shared pointers are used hereor作用域指针.Since scope pointers are defined as not copyable,So using it directly also saves the code for declaring private copy constructs and operators.
#include <string>
class AutoTimer
{
public:
explicit AutoTimer(const std::string& name);
~AutoTimer();
private:
class Impl;
boost::scoped_ptr<Impl> mImpl;
// 如果使用shared_ptrYou need to write your own copy constructs and operators
}
Pimpl优缺点总结
优点:
1、信息隐藏
2、降低耦合
3、加速编译:Implement file move in.cpp降低了apicitation hierarchy,Directly affects compile time
4、二进制兼容性:Any modification to member variables is forPimplThe size of the object pointer is always the same
5、惰性分配:mImplClasses can be restructured when needed
缺点:
1、增加了ImplClass allocation and deallocation,May introduce performance conflicts.
2、Accessing all private members requires a layer outsidemImpl→,This complicates the code.
边栏推荐
猜你喜欢
随机推荐
typescript24-类型推论
This article takes you to understand the past and present of Mimir, Grafana's latest open source project
风险策略调优中重要的三步分析法
Simple and easy to use task queue - beanstalkd
出现Command ‘vim‘ is available in the following places,vim: command not found等解决方法
Immutable
【无标题】
移动端页面秒开优化总结
button去除黑框
Introduction to Oracle
软件测试周刊(第82期):其实所有纠结做选择的人心里早就有了答案,咨询只是想得到内心所倾向的选择。
在互联网时代,有诸多「互联网+」模式的诞生
云服务器下载安装mongo数据库并远程连接详细图文版本(全)
请问表格储存中用sql只能查询到主键列,ots sql非主键不支持吗?
leetcode:126. Word Solitaire II
今日睡眠质量记录68分
对无限debugger的一种处理方式
基于ProXmoX VE的虚拟化家庭服务器(篇一)—ProXmoX VE 安装及基础配置
【愚公系列】2022年07月 .NET架构班 085-微服务专题 Abp vNext微服务网关
最新 955 不加班的公司名单









