如何解决Code Complete关于封装的C ++建议?
| 在“代码完成”中有关“良好封装”的部分中,建议隐藏私有实现详细信息。用C ++给出了一个例子。这个想法基本上是将接口与实现完全分开,即使在类级别也是如此。class Employee {
public:
...
Employee( ... );
...
FullName GetName() const;
String GetAddress() const;
private:
EmployeeImplementation *m_implementation;
};
这真的是时间的好利用吗?这不仅效率低下(这会给性能带来什么样的损失?),而且代码完整性(“管理复杂性”)的座右铭似乎已经被颠倒了-这不会增加复杂性吗?
解决方法
PIMPL惯用语的另一个优势可能在于维护ABI。请参阅实践中的“ Pimpl成语”。
类的大小保持不变。这意味着您可以更改内部实现,同时保持接口完整。
如果实现以编译形式(lib,dll等)分发,则在某些情况下,您可能只需要替换库而不必重新编译使用该类的代码。因此,只要公共接口不变,就可以将代码解耦为一个完全独立的模块。
正如其他人所述,它还减少了编译时间,在某些情况下这可能是足够的理由。
, 好吧,由于您的头文件现在仅包含公共成员和一个指向私有实现的指针,因此它确实增加了封装。
由于额外的间接级别,它还会(略微?)降低性能。
“减少编译时间”是这里的关键问题。
如果您(您的公司)是该类的唯一用户,那么我认为您没有任何理由使用此习语。您将获得较低的性能,并且无论如何都应该每天(或定期)重建源代码(应该知道类之间的依赖关系)。
这意味着,如果您是该类的唯一使用者,则编译时间在很大程度上无关紧要。
如果您要分发库,那么情况就完全不同了。标头的更改意味着即使您更改了类的私有部分,您拥有的任何客户端也都需要重建其应用程序才能使用新版本。在这里使用pimpl惯用语意味着更改对动态库的用户是不可见的。
, 通过指针进行的间接间接访问会导致额外的高速缓存未命中,并降低程序速度。 AFAIK,最常建议使用此惯用法(PIMPL)以减少编译时间。假设您有一个
employee.h
头,其中包含类中的所有字段,而不仅仅是一个指针。现在,无论何时更改员工详细信息(例如,添加或删除字段),都必须重新编译每个文件,包括employee.h
。如果您只有一个指向employee.cpp
中定义的实现类的指针,则在更改EmployeeImplementation
时仅需重新编译employee.cpp
。
现在,减少的编译时间值得增加成本吗?只有您可以决定。
, 我认为pimpl习惯用法的主要优点(或至少其中一项)不是节省编译时间,而是允许组件之间的松耦合,即打破依赖关系。
假设您提供了许多其他组件使用的基础结构库。然后,如@zvrba所示,每次更改私有实现详细信息时,所有客户端都必须重新编译。这可能没什么大不了的,但是在大型复杂项目中,组件之间的集成可能是一项复杂的任务。使用pimpl,如果您的库是动态的(dll,.so),则客户端不需要任何操作。
, 这个习语用于对较差的标头进行抽象,仅此而已。仅在定义类所需的类型涉及包括泄漏宏的标头,需要很长时间才能编译的标头等情况下才使用它。除此之外,通常不认为这样做是正确的。由于您的实现无论如何都需要动态分配和引用语义,因此您也可以使其成为接口并提供在cpp文件中具有定义的CreateForMyPlatform()
方法。至少您可以在这种情况下使用智能指针。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。