使用包含类数据的PrivateClass的好处是什么?
What are benefits of using PrivateClass containing data of the Class?
class MyClassPrivate
{
//My members.
};
//and then
class MyClass {
private:
MyClassPrivate* const d;
};
使用这种"模式"的原因是什么?它的正确叫法是什么?
这被称为"指针实现"或"pimpl"。见http://en.wikibooks.org/wiki/C + + _Programming/成语# Pointer_To_Implementation_.28pImpl.29
当你使用这种模式时,你将向前声明实现类,并在其他地方声明主体,即:
// header
class MyClassPrivate;
class MyClass {
public:
MyClass();
~MyClass();
private:
MyClassPrivate* const d;
};
// cpp
class MyClassPrivate {
};
MyClass::MyClass() : d(new MyClassPrivate) {}
MyClass::~MyClass() { delete d; }
这样做的好处是MyClass
的实现不会暴露给MyClass
的其他用户。如果实现改变,MyClass
的其他用户不需要重新编译。任何必须为成员包含的头文件也不需要公开,这样可以缩短编译时间。
使用最多的是Pimlp成语。
- 为什么要使用"PIMPL"习惯用法? <
- Pimpl成语/gh>
- Pimpl
从这里Pimpl习语描述了一种制作头文件的方法不受变化影响的。你经常听到这样的建议:"避免改变你的公共接口!"所以你可以修改你的私有接口,但是如何当你的头文件定义了私有属性时,你能避免重新编译吗方法。这就是Pimpl做什么-减少编译损害时你的私有接口改变了[3].
:
好处:
- 更改类的私有成员变量不需要重新编译依赖它的类,从而使时间更快,并且减少了FragileBinaryInterfaceProblem。
- 头文件不需要#include在私有成员变量中"按值"使用的类,因此编译时间更快。 这有点像SmallTalk自动处理类的方式…更纯的封装。
缺点:
- 实现者还有更多的工作要做。
- 对于需要子类访问的"protected"成员不起作用。
- 有点难读代码,因为一些信息不再在头文件。
- 运行时的性能会因为指针的间接而受到轻微的影响,特别是如果函数调用是虚拟的(间接分支的分支预测通常很差)。
怎么做:
- 将所有私有成员变量放入一个结构体中。
- 将结构体定义放在。cpp文件中。
- 在头文件中,只放入结构体的ForwardDeclaration。
- 在类定义中,声明一个(智能)指针作为唯一的私有成员变量。
- 类的构造函数需要创建这个结构体。
- 类的析构函数需要销毁该结构(可能由于使用智能指针而隐式地销毁)。
- 赋值操作符和CopyConstructor需要适当地复制结构体,否则将被禁用。
当您希望将接口与实现分离时,您可以将其用于PIMPL习语。
许多设计模式也使用指向私有属性的"指针",例如策略模式。此模式允许您在运行时选择不同的算法。同样,如果你让数据的操作遵循相同的接口,你可以将数据封装在一个Private Class中,使这个类成为层次结构的一部分,并在运行时(或编译时)在不同的数据实现之间切换。
一个很好的例子是保存多边形数据的几何类。每个多边形都提供对点的访问,您还可以删除多边形边缘并执行各种其他拓扑操作。如果你用deletePoint, addPoint, swapEdge等方法为Polygon类提供一个抽象基类,你可以测试不同的Polygon实现。可以直接将多边形定义为Point类型的列表,并将这些点存储在不同的容器中(list或vector)。Polygon类可以通过间接寻址来定义,其中多边形实际上是点列表的id列表(我谈论的是一般意义上的列表)。这样,你就可以测试PolygonGeometry类的不同算法,看看它们是如何在不同的多边形实现中工作的。
这背后有一个设计原则:更喜欢组合而不是继承。当你使用Composition并且依赖于在运行时确定的类型时,你将拥有一个私有属性指针。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么