【C++】Pimpl-创新互联
目录
创新互联公司是一家集网站建设,凌河企业网站建设,凌河品牌网站建设,网站定制,凌河网站建设报价,网络营销,网络优化,凌河网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。一、Pimpl
二、Pimpl的实现
三、Pimpl的优缺点
1、Pimpl优点
2、Pimpl缺点
总结
一、Pimpl
Pimpl术语,即“pointer to implementation”(指向实现的指针),由Jeff Summer最先引入。该技巧可以避免在头文件中暴露私有细节,是促进API接口和实现保持完全分离的重要机制。
Pimpl并不是严格意义上的设计模式,而是桥接模式的一种特例。
它的目的是将文件间的编译依存关系降至最低,如果没有降低文件间的依存关系,这些头文件中有任何一个被改变,或者这些头文件所依赖的其他头文件有任何改变,那么任何使用该文件的文件也必须重新编译,这样的连串编译依存关系,会对许多项目造成难以形容的灾难
而我们可以将对象实现细节隐藏于一个指针背后,这样使编译依赖关系降到最低
二、Pimpl的实现Pimpl的本质是把一个类分割成两个类,一个类只提供接口,另一个类负责实现该接口
Pimpl的实现有两种,一种是将所有private成员放在一个class/struct中,这个类在头文件中仅做前置声明,在.cpp中定义。
#pragma once
#include#include#includeclass Date;
class Address;
class Person
{
public:
Person(const std::string &name, const Date &birthday,
const std::string &addr);
std::string name() const;
std::string birthDate() const;
std::string Address() const;
private:
class PersonImpl;//前置声明
std::unique_ptr_pImpl;
};
这里使用PersonImpl来实现Person类内部的所有细节
同时使用_pImpl指针来辅助访问Person类内部,为了避免内存泄露,所以使用智能指针来管理那个资源
//Date类的简单实现
class Date
{
public:
Date(int year = 1970, int month = 1, int day = 1)
: _year(year), _month(month), _day(day)
{
}
std::string GetDate() const
{
return std::to_string(_year) + "/" + std::to_string(_month) + "/" + std::to_string(_day);
}
private:
int _year;
int _month;
int _day;
};
实现细节
struct Person::PersonImpl
{
std::string _name;
Date _birthday;
std::string _address;
};
Person::Person(const std::string &name, const Date &birthday,
const std::string &addr)
: _pImpl(new PersonImpl)
{
_pImpl->_name = name;
_pImpl->_birthday = birthday;
_pImpl->_address = addr;
}
std::string Person::name() const
{
return _pImpl->_name;
}
std::string Person::birthDate() const
{
return _pImpl->_birthday.GetDate();
}
std::string Person::Address() const
{
return _pImpl->_address;
}
#include "Person.hpp"
#include "comm.hpp"
int main()
{
Person p1("张三", Date(2002, 3, 5), "北京");
std::cout<< p1.name()<< std::endl;
std::cout<< p1.birthDate()<< std::endl;
std::cout<< p1.Address()<< std::endl;
return 0;
}
这种实现方式在上层使用与直接在Person类内部实现没有区别
另一种实现方式是令Person成为一种特殊的抽象类
class Date;
//interface class
class Person
{
public:
static std::shared_ptrCreate(const std::string& name, const Date& birthday, const std::string& addr);
virtual ~Person();
virtual std::string name() const = 0;
virtual std::string birthDate() const = 0;
virtual std::string Address() const = 0;
};
类中除了Create函数声明为静态,其它所有的成员函数声明为纯虚方法,且类中没有成员变量
#pragma once
#include "Person.hpp"
class Date
{
public:
Date(int year = 1970, int month = 1, int day = 1)
: _year(year), _month(month), _day(day)
{
}
std::string GetDate() const
{
return std::to_string(_year) + "/" + std::to_string(_month) + "/" + std::to_string(_day);
}
private:
int _year;
int _month;
int _day;
};
class RealPerson : public Person
{
public:
RealPerson(const std::string &name, const Date &birthday, const std::string &addr)
: _theName(name), _theBirthdate(birthday), _theAdder(addr)
{
}
virtual ~RealPerson();
virtual std::string name() const;
virtual std::string birthDate() const;
virtual std::string Address() const;
private:
std::string _theName;
Date _theBirthdate;
std::string _theAdder;
};
std::shared_ptrPerson::Create(const std::string& name, const Date& birthday, const std::string& addr)
{
return std::shared_ptr(new RealPerson(name, birthday, addr));
}
RealPerson::~RealPerson()
{
}
std::string RealPerson::name() const
{
return _theName;
}
std::string RealPerson::birthDate() const
{
return _theBirthdate.GetDate();
}
std::string RealPerson::Address() const
{
return _theAdder;
}
这里的Create函数的实现借助于它的派生类,因为派生类只继承了它的接口,并且Person类成员变量全部在RealPerson中,进一步屏蔽了Person类的实现细节
返回时返回的是它的派生类类型的智能指针,通过C++的切片,就可以安全的获得Person类
#include "Person.hpp"
#include "comm.hpp"
int main()
{
std::shared_ptrpp(Person::Create("张三", Date(2002, 3, 5), "北京"));
std::cout<< pp->name()<< std::endl;
std::cout<< pp->birthDate()<< std::endl;
std::cout<< pp->Address()<< std::endl;
return 0;
}
三、Pimpl的优缺点
1、Pimpl优点信息隐藏
实现细节可以隐藏到Impl类实现中,保护闭源API专有性。同时,接口头文件也能更干净、清晰表达真正的公有接口,易于阅读和理解。降低耦合
接口类只用知道Impl类即可,不用包含私有成员变量所需头文件,也不必包含平台依赖的windows.h或sys/time.h。加速编译
将实现相关头文件移入.cpp,API的引用层次降低,会导致编译时间减少。更好的二进制兼容性
采用Pimpl的对象大小从不改变,因为对象总是单个指针大小。对私有成员变量做任何修改,都只影响隐藏在cpp文件内的实现类大小。而对象的二进制表示可以不变。惰性分配
Impl类可以在需要时再构造,而不必在接口类构造时立即构造。
1)必须为你创建的每个对象分配并释放实现对象。这使得对象增加了一个指针(Impl* impl_),同时增加了通过指针访问成员的开销,增加了new和delete对象的开销。
2)必须通过impl_->的形式访问私有成员,给开发人员带来了不便。
3)编译器不能捕获接口类中const对成员变量修改。因为成员变量现在存在于独立的对象(impl_指针所指对象)中。编译器仅检查impl_指针是否发生变化,而不会检查其成员。
总结
如果只是因为若干成本原因而放弃使用Pimpl是严重错误的,virtual也带来了若干成本,应该以渐进的方式使用这些技术,在工程中使用以求得代码有所变化时对服务带来最小冲击
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网站名称:【C++】Pimpl-创新互联
当前链接:http://ybzwz.com/article/dcpeoi.html