我必须使用一个界面非常笨拙的旧类。由于我无法更改它并且依赖它,因此我想构建一个包装器,提供一个干净的界面。假设我有课笨手笨脚的班级。基本上,我有三种方法:
1. 参考会员
Class Wrapper {
public:
Wrapper (ClumsyClass& clumsyClass)
: m_clumsyClass(clumsyClass)
{ }
int getSmth() {
return m_clumsyClass.getSmth();
}
private:
ClumsyClass& m_clumsyClass;
}
2. 指针成员
Class Wrapper {
public:
Wrapper (ClumsyClass* clumsyClass)
: m_clumsyClass(clumsyClass)
{ }
int getSmth() {
return m_clumsyClass->getSmth();
}
private:
ClumsyClass* m_clumsyClass;
}
3、继承
Class Wrapper : public ClumsyClass {
...
}
哪种方法是实现包装器的“最干净”方法?我更喜欢第三个,但是当我已经有一个 ClumsyClass 对象然后创建一个 Wrapper 对象(复制构造函数)时,将需要更多内存(因为在我的情况下需要原始类的实例)。
我会避免使用 3,因为它无法封装ClumsyClass
。用户Wrapper
可以有意或无意地直接访问“笨拙”的界面ClumsyClass
这就是你想要避免的。优先选择组合而不是继承。
1. 和 2. 之间的差异很小。使用参考构件会降低包装器的灵活性。该类不可分配,您无法重新设置引用并将其替换为不同的实例ClumsyClass
并且该成员不能为空。这些可能是好事也可能是坏事,具体取决于您的要求。
但正如评论中提到的,默认选择可能应该是ClumsyClass
作为按值成员Wrapper
:
class Wrapper {
public:
// possible constructors
//Wrapper(const ClumsyClass& cc) : m_clumsyClass(cc) {} // copy
//Wrapper(ClumsyClass&& cc) : m_clumsyClass(std::move(cc)) {} // move
int getSmth() { return m_clumsyClass.getSmth(); }
private:
ClumsyClass m_clumsyClass;
};
在您的特定用例中,有多种原因可能导致这种情况不可能或不理想,然后您可以回退到选项 1 或 2。该决定主要取决于所有权。应该Wrapper
“拥有”ClumsyClass
还是实例ClumsyClass
有一个生命之外的生命Wrapper
?
使用直接成员的一个潜在缺点是您无法再隐藏以下实现ClumsyClass
在前向声明后面,这样你就失去了一些封装ClumsyClass
。值得注意的是,解决这个问题的一种方法是提取一个抽象基类“接口”,Wrapper
继承自.就像是:
class IWrapper {
public:
virtual ~IWrapper() {}
virtual int getSmth() = 0;
};
这可能会提供额外的好处,例如可测试性。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)